ruby input output
¿Mejores prácticas con STDIN en Ruby? (9)
Quiero lidiar con la entrada de línea de comandos en Ruby:
> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...
¿Cuál es la mejor manera de hacerlo? En particular, quiero lidiar con STDIN en blanco, y espero una solución elegante.
#!/usr/bin/env ruby
STDIN.read.split("/n").each do |a|
puts a
end
ARGV.each do |b|
puts b
end
¿Algo así tal vez?
#/usr/bin/env ruby
if $stdin.tty?
ARGV.each do |file|
puts "do something with this file: #{file}"
end
else
$stdin.each_line do |line|
puts "do something with this line: #{line}"
end
end
Ejemplo:
> cat input.txt | ./myprog.rb
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb < input.txt
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb arg1 arg2 arg3
do something with this file: arg1
do something with this file: arg2
do something with this file: arg3
A continuación hay algunas cosas que encontré en mi colección de Ruby oscuro.
Por lo tanto, en Ruby, una implementación simple sin complicaciones del comando cat
Unix sería:
#!/usr/bin/env ruby
puts ARGF.read
ARGF
es tu amigo cuando se trata de entrada; es un archivo virtual que obtiene todas las entradas de los archivos nombrados o todos los de STDIN.
ARGF.each_with_index do |line, idx|
print ARGF.filename, ":", idx, ";", line
end
# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
puts line if line =~ /login/
end
Gracias a Dios, no conseguimos el operador de diamantes en Ruby, pero sí ARGF
como reemplazo. Aunque oscuro, en realidad resulta útil. Considere este programa, que antepone encabezados de copyright en el lugar (gracias a otro Perlism, -i
) a cada archivo mencionado en la línea de comandos:
#!/usr/bin/env ruby -i
Header = DATA.read
ARGF.each_line do |e|
puts Header if ARGF.pos - e.length == 0
puts e
end
__END__
#--
# Copyright (C) 2007 Fancypants, Inc.
#++
Crédito a:
Agregaré que para usar ARGF
con parámetros, debe borrar ARGV
antes de llamar a ARGF.each
. Esto se debe a que ARGF
tratará cualquier cosa en ARGV
como un nombre de archivo y leerá las líneas desde allí primero.
Aquí hay un ejemplo de implementación ''tee'':
File.open(ARGV[0], ''w'') do |file|
ARGV.clear
ARGF.each do |line|
puts line
file.write(line)
end
end
Hago algo como esto:
all_lines = ""
ARGV.each do |line|
all_lines << line + "/n"
end
puts all_lines
No estoy muy seguro de lo que necesita, pero usaría algo como esto:
#!/usr/bin/env ruby
until ARGV.empty? do
puts "From arguments: #{ARGV.shift}"
end
while a = gets
puts "From stdin: #{a}"
end
Tenga en cuenta que dado que la matriz ARGV está vacía antes de la primera obtención, Ruby no intentará interpretar el argumento como un archivo de texto para leer (comportamiento heredado de Perl).
Si la entrada estándar está vacía o no hay argumentos, no se imprime nada.
Pocos casos de prueba:
$ cat input.txt | ./myprog.rb
From stdin: line 1
From stdin: line 2
$ ./myprog.rb arg1 arg2 arg3
From arguments: arg1
From arguments: arg2
From arguments: arg3
hi!
From stdin: hi!
Parece que la mayoría de las respuestas están asumiendo que los argumentos son nombres de archivos que contienen contenido que debe incluirse en la entrada estándar. A continuación todo se trata como argumentos justos. Si STDIN es del TTY, entonces se ignora.
$ cat tstarg.rb
while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
puts a
end
Cualquiera de los argumentos o stdin puede estar vacío o tener datos.
$ cat numbers
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
Rápido y simple:
STDIN.gets.chomp == ''YES''
Ruby proporciona otra forma de manejar STDIN: la bandera -n. Considera que todo su programa está dentro de un bucle sobre STDIN (incluidos los archivos pasados como argumentos de la línea de comandos). Ver, por ejemplo, el siguiente script de 1 línea:
#!/usr/bin/env ruby -n
#example.rb
puts "hello: #{$_}" #prepend ''hello:'' to each line from STDIN
#these will all work:
# ./example.rb < input.txt
# cat input.txt | ./example.rb
# ./example.rb input.txt
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
Esto está inspirado en Perl:
while(<STDIN>){
print "$_/n"
}