Ruby'de en iyi STDIN uygulamaları?


307

Ruby komut satırı girdisi ile uğraşmak istiyorum:

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

Bunu yapmanın en iyi yolu ne? Özellikle boş STDIN ile uğraşmak istiyorum ve şık bir çözüm umuyorum.

#!/usr/bin/env ruby

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

ARGV.each do |b|
    puts b
end

5
Sadece küçük bir not: Verdiğiniz ilk iki komut satırı şu açıdan tamamen aynıdır myprog.rb: input.txtdosya stdin'e eklenir ; kabuk bunu sizin için yönetir.
Mei

6
^ ^ ^ bu genellikle "kedinin yararsız kullanımı" olarak adlandırılır, bunu çok göreceksiniz.
Steve Kehlet

18
@SteveKehlet Ancak daha akıllıca "kedi istismarı" olarak adlandırılır inanıyorum
OneChillDude

Yanıtlar:


403

Karanlık Ruby koleksiyonumda bulduğum bazı şeyler aşağıda.

Yani, Ruby'de, Unix komutunun zilsiz basit bir uygulaması catşöyle olur:

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

ARGFgirdi söz konusu olduğunda arkadaşınızdır; adlandırılmış dosyalardan veya STDIN'den gelen tüm girdileri alan sanal bir dosyadır.

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

Şükür biz Ruby elmas operatörü alamadım, ama yerine aldık ARGF. Karanlık olmasına rağmen, aslında yararlı olduğu ortaya çıkıyor. -iKomut satırında belirtilen her dosyaya (başka bir Perlism sayesinde) telif hakkı başlıklarını yerinde ekleyen bu programı düşünün :

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

Kredi:


12
ARGF gidilecek yol. Ruby, dosyaları ve stdin'i çok yönlü bir şekilde ele alacak şekilde üretilmiştir.
Pistos

1
(bunu gördüm ve seni düşündüm) şu kredilerle ilgili: blog.nicksieger.com/articles/2007/10/06/…
deau

Bu çok iyi. AWK'nin çalışma şeklini simüle etmek için güzel bir model varsa (sıfır veya minimum interlocution ile) günüm tamamlanacak. :-)
will

Belki de, idxher bir dosya için satır numarası yerine, tüm girişleri birleştiren sanal dosyadaki "satır numarası" olacağını unutmayın .
Alec Jacobson

Bu #!/usr/bin/env ruby -isatırın Linux'ta çalışmadığını unutmayın : stackoverflow.com/q/4303128/735926
bfontaine

43

Ruby, STDIN: -n bayrağıyla baş etmenin başka bir yolunu sunar. Tüm programınızı STDIN üzerinden bir döngü içinde (komut satırı argümanları olarak iletilen dosyalar dahil) olarak ele alır. Bkz. Örneğin aşağıdaki 1 satırlık komut dosyası:

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

8
#!/usr/bin/env ruby -n"Yakut-n" tek argüman olarak / usr / bin / env'ye aktarılacağı için üç parterli shebang çalışmaz. Daha fazla ayrıntı için bu cevaba bakınız. Senaryo olacak olan çalıştırırsanız çalışmak ruby -n script.rbaçıkça.
artm

5
@jdizzle: OSX üzerinde çalışıyor, ancak Linux'ta çalışmıyor - ve sorun tam olarak bu: taşınabilir değil .
mklement0

32

Neye ihtiyacınız olduğundan emin değilim, ama böyle bir şey kullanırdım:

#!/usr/bin/env ruby

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

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

ARGV dizisi ilk önce boş olduğu için gets, Ruby'nin bağımsız değişkeni okunacak metin dosyası olarak yorumlamaya çalışmadığını unutmayın (Perl'den devralınan davranış).

Stdin boşsa veya argüman yoksa, hiçbir şey yazdırılmaz.

Birkaç test vakası:

$ 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!

18

Belki böyle bir şey?

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

Misal:

> 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

metin olmaya gerek yok. Notorius metin değil, örneğin bir çeşit sıkıştırma / sıkıştırmadır. (each_line sadece ascii için hazırlanıyor). her_bayt belki?
Jonke

12
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

Bu ilham Perl:

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

4
Basitlik ve okunabilirlik için cehennem evet! Oh hayır, bekle, bu '$ _' nedir? Lütfen Stack Overflow'da İngilizce kullanın !


1

Bunu ARGFparametrelerle kullanmak için ARGVaramadan önce temizlemeniz gerektiğini ekleyeceğim ARGF.each. Bunun nedeni ARGF, her şeyi ARGVbir dosya adı olarak ele alıp önce oradan satırları okuyacağıdır.

Örnek bir 'tee' uygulaması:

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

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

1

Böyle bir şey yapıyorum:

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

0

Çoğu cevap, argümanların stdin'e katıştırılacak içerik içeren dosya adları olduğunu varsayar. Her şeyin altında sadece argümanlar olarak ele alınır. STDIN TTY'den geliyorsa, yok sayılır.

$ cat tstarg.rb

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

Bağımsız değişkenler veya stdin boş olabilir veya veri içerebilir.

$ cat numbers 
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.