web-dev-qa-db-de.com

Best Practices mit STDIN in Ruby?

Ich möchte mich mit der Befehlszeileneingabe in Ruby befassen:

> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...

Was ist der beste Weg, dies zu tun? Insbesondere möchte ich mich mit Blank STDIN beschäftigen und hoffe auf eine elegante Lösung.

#!/usr/bin/env Ruby

STDIN.read.split("\n").each do |a|
   puts a
end

ARGV.each do |b|
    puts b
end
293
griflet

Nachfolgend einige Dinge, die ich in meiner Sammlung von obskurer Ruby gefunden habe.

In Ruby wäre also eine einfache Implementierung des Unix-Befehls cat ohne Glocken:

#!/usr/bin/env Ruby
puts ARGF.read

ARGF ist dein Freund, wenn es um Eingabe geht; Es ist eine virtuelle Datei, die alle Eingaben von benannten Dateien oder alle von STDIN erhält.

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

Zum Glück haben wir den Diamantenoperator nicht in Ruby bekommen, aber wir haben ARGF als Ersatz erhalten. Obwohl es dunkel ist, erweist es sich tatsächlich als nützlich. Stellen Sie sich dieses Programm vor, das urheberrechtlich geschützte Kopfzeilen (dank eines anderen Perlismus, -i) vor jeder in der Befehlszeile genannten Datei anfügt:

#!/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.
#++

Gutschrift an:

387
Jonke

Ruby bietet eine weitere Möglichkeit, mit STDIN umzugehen: Das Flag -n. Es behandelt Ihr gesamtes Programm als innerhalb einer Schleife über STDIN (einschließlich Dateien, die als Befehlszeilenargumente übergeben werden). Siehe z. das folgende einzeilige Skript:

#!/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
40
Bill Caputo

Ich bin mir nicht ganz sicher, was Sie brauchen, aber ich würde so etwas verwenden:

#!/usr/bin/env Ruby

until ARGV.empty? do
  puts "From arguments: #{ARGV.shift}"
end

while a = gets
  puts "From stdin: #{a}"
end

Beachten Sie, dass das ARGV-Array vor der ersten gets leer ist, versucht Ruby nicht, Argument als Textdatei zu interpretieren, aus der gelesen werden soll (Verhalten, das von Perl geerbt wurde).

Wenn stdin leer ist oder keine Argumente vorhanden sind, wird nichts gedruckt.

Einige Testfälle:

$ 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!
31
Damir Zekić

So etwas vielleicht?

#/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

Beispiel:

> 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
17
Magnus Holm
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

Dies ist von Perl inspiriert:

while(<STDIN>){
  print "$_\n"
}
11
texasbruce

Es scheint, als würden die meisten Antworten davon ausgehen, dass die Argumente Dateinamen sind, die den Inhalt enthalten, der an die Standardanwendung übergeben werden soll. Darunter wird alles nur als Argument behandelt. Wenn STDIN vom TTY stammt, wird es ignoriert.

$ cat tstarg.rb

while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
  puts a
end

Argumente oder stdin können leer sein oder Daten enthalten.

$ cat numbers 
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
1
Howard Barina

Ich mache so etwas: 

all_lines = ""
ARGV.each do |line|
  all_lines << line + "\n"
end
puts all_lines
1
wired00

Ich füge hinzu: Um ARGF mit Parametern zu verwenden, müssen Sie ARGV löschen, bevor Sie ARGF.each aufrufen. Dies liegt daran, dass ARGF alles in ARGV als Dateinamen behandelt und zuerst Zeilen von dort liest.

Hier ist ein Beispiel für eine Implementierung von 'tee':

File.open(ARGV[0], 'w') do |file|
  ARGV.clear

  ARGF.each do |line|
    puts line
    file.write(line)
  end
end
1

Schnell und einfach:

STDIN.gets.chomp == 'YES'

0
Jose Alban