रूबी में STDIN के साथ सर्वोत्तम अभ्यास?


307

मैं रूबी में कमांड लाइन इनपुट से निपटना चाहता हूं:

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

यह करने के लिए सबसे अच्छा तरीका क्या है? विशेष रूप से मैं खाली STDIN से निपटना चाहता हूं, और मैं एक सुरुचिपूर्ण समाधान की उम्मीद करता हूं।

#!/usr/bin/env ruby

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

ARGV.each do |b|
    puts b
end

5
बस एक छोटी सी टिप्पणी: आपके द्वारा दी गई पहली दो कमांड लाइनें दृश्य के दृष्टिकोण से बिल्कुल समान हैं myprog.rb: input.txtफ़ाइल स्टड से जुड़ी हुई है ; शेल आपके लिए इसे प्रबंधित करता है।
मेई

6
^ ^ इसे अक्सर "बिल्ली के बेकार उपयोग" के रूप में संदर्भित किया जाता है, आप देखेंगे कि बहुत कुछ।
स्टीव केहलेट

18
@SteveKehlet हालांकि मेरा मानना ​​है कि इसे अधिक चतुराई से "बिल्ली के साथ दुर्व्यवहार" के रूप में जाना जाता है
OneChillDude

जवाबों:


403

निम्नलिखित कुछ चीजें हैं जो मुझे अस्पष्ट रूबी के संग्रह में मिली हैं।

तो, रूबी में, यूनिक्स कमांड का एक सरल नो-बेल कार्यान्वयन catहोगा:

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

ARGFजब यह इनपुट की बात आती है तो आपका मित्र है; यह एक आभासी फ़ाइल है जिसे सभी इनपुट नामित फ़ाइलों या सभी 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

शुक्रिया, हमें रूबी में हीरा ऑपरेटर नहीं मिला, लेकिन हम ARGFप्रतिस्थापन के रूप में मिले। हालांकि अस्पष्ट है, यह वास्तव में उपयोगी साबित होता है। इस कार्यक्रम पर विचार करें, जो -iकमांड-लाइन पर उल्लिखित प्रत्येक फ़ाइल के लिए कॉपीराइट हेडर इन-प्लेस (एक और पर्लिज़्म के लिए धन्यवाद ) प्रस्तुत करता है:

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

को श्रेय:


12
ARGF जाने का रास्ता है। यह रूबी की तरह से बनाया गया है जो फाइलों को संभालता है और एक चौतरफा फैशन में है।
पिस्तोस नोव

1
(यह देखा और आप के बारे में सोचा) उन क्रेडिट: blog.nicksieger.com/articles/2007/10/06/…
deau

यह बहुत अच्छा है। अगर AWK के काम करने के तरीके (शून्य या न्यूनतम इंटरकोर्स के साथ) को अनुकरण करने के लिए एक अच्छा पैटर्न है तो मेरा दिन पूरा हो जाएगा। :-)
होगा

शायद ध्यान दें कि idxवर्चुअल फ़ाइल में "लाइन नंबर" होगा जो किसी भी व्यक्तिगत फ़ाइल के लिए लाइन नंबर के बजाय सभी इनपुट को समाप्‍त करता है।
एलेक जैकबसन

ध्यान दें कि यह #!/usr/bin/env ruby -iलाइन लिनक्स पर काम नहीं करती है: stackoverflow.com/q/4303128/735926
bfontaine

43

रूबी STDIN को संभालने के लिए एक और तरीका प्रदान करती है: -n झंडा। यह एसटीडीआईएन पर एक लूप के अंदर होने के रूप में आपके पूरे कार्यक्रम को मानता है, (कमांड लाइन आर्ग्स के रूप में पारित फ़ाइलों सहित)। निम्न 1-लाइन स्क्रिप्ट उदाहरण देखें:

#!/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काम नहीं करेगा, क्योंकि "रूबी-एन" केवल तर्क के रूप में / usr / bin / env को पारित किया जाएगा। अधिक विवरण के लिए यह उत्तर देखें। यदि स्पष्ट रूप से चलाया जाता है तो स्क्रिप्ट काम करेगीruby -n script.rb
आर्टेम

5
@jdizzle: यह OSX पर काम करता है, लेकिन लिनक्स पर नहीं - और यह वास्तव में समस्या है: यह पोर्टेबल नहीं है ।
mklement0

32

मुझे यकीन नहीं है कि आपको क्या चाहिए, लेकिन मैं कुछ इस तरह का उपयोग करूंगा:

#!/usr/bin/env ruby

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

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

ध्यान दें कि क्योंकि ARGV सरणी पहले से खाली है gets, रूबी तर्क को पाठ फ़ाइल के रूप में व्याख्या करने का प्रयास नहीं करेगी, जिसमें से पढ़ने के लिए (पर्ल से विरासत में मिला व्यवहार)।

अगर स्टड खाली है या कोई तर्क नहीं है, कुछ भी नहीं छपा है।

कुछ परीक्षण मामले:

$ 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

शायद ऐसा ही कुछ?

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

उदाहरण:

> 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

स्टड पाठ की जरूरत नहीं है। Notorius पाठ नहीं है उदाहरण के लिए कुछ प्रकार के संपीड़ित / असंपीड़ित। (प्रत्येक_लाइन केवल आस्की की तैयारी की तरह है)। हो सकता है?
जॉनके

12
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

यह पर्ल से प्रेरित है:

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

4
नरक हाँ, सादगी और पठनीयता के लिए! अरे नहीं, रुको, वह '$ _' क्या है? स्टैक ओवरफ्लो पर अंग्रेजी का उपयोग करें !


1

मैं जोड़ूंगा कि ARGFमापदंडों के साथ उपयोग करने के लिए , आपको ARGVकॉल करने से पहले स्पष्ट करने की आवश्यकता है ARGF.each। ऐसा इसलिए है क्योंकि ARGFकिसी भी चीज़ ARGVको एक फ़ाइल नाम के रूप में माना जाएगा और पहले वहां से लाइनें पढ़ें।

यहाँ एक उदाहरण 'टी' कार्यान्वयन है:

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

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

1

मैं ऐसा कुछ करता हूं:

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

0

ऐसा लगता है कि अधिकांश उत्तर यह मान रहे हैं कि तर्कों को फिल्माया जा रहा है जिसमें स्टड के लिए सामग्री होगी। नीचे सब कुछ सिर्फ तर्कों के रूप में माना जाता है। यदि STDIN TTY से है, तो इसे अनदेखा कर दिया जाता है।

$ cat tstarg.rb

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

या तो तर्क या स्टड खाली हो सकता है या डेटा हो सकता है।

$ cat numbers 
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.