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
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:
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
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!
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
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
Dies ist von Perl inspiriert:
while(<STDIN>){
print "$_\n"
}
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
Ich mache so etwas:
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
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
Schnell und einfach:
STDIN.gets.chomp == 'YES'