2010-07-07 7 views
7

में फ़ाइल की सामग्री से लूप ठीक है, इसलिए मैं रूबी के लिए नया हूं और मेरे पास बैश/ksh/sh में एक मजबूत पृष्ठभूमि है।रूबी

जो मैं करने की कोशिश कर रहा हूं वह लूप के लिए कई सर्वरों पर एक कमांड चलाने के लिए सरल है। बैश में मुझे यह पसंद करना होगा:

server1 
server2 
server3 
etc 

मैं रूबी में यह अधिकार प्राप्त करने के लिए प्रतीत नहीं कर सकते हैं:

for SERVER in `cat etc/SERVER_LIST` 
do 
    ssh -q ${SERVER} "ls -l /etc" 
done 

etc/SERVER_LIST सिर्फ एक फ़ाइल लग रहा है कि तरह है।

#!/usr/bin/ruby 
### SSH testing 
# 
# 

require 'net/ssh' 

File.open("etc/SERVER_LIST") do |f| 
     f.each_line do |line| 
       Net::SSH.start(line, 'andex') do |ssh| 
         result = ssh.exec!("ls -l") 
         puts result 
       end 
     end 
end 

मैं इन त्रुटियों को अब हो रही है::

[email protected]:~/sysauto> ./ssh2.rb 
/usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize': newline at the end of hostname (SocketError) 
     from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `open' 
     from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize' 
     from /usr/lib64/ruby/1.8/timeout.rb:53:in `timeout' 
     from /usr/lib64/ruby/1.8/timeout.rb:93:in `timeout' 
     from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize' 
     from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh.rb:179:in `new' 
     from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh.rb:179:in `start' 
     from ./ssh2.rb:10 
     from ./ssh2.rb:9:in `each_line' 
     from ./ssh2.rb:9 
     from ./ssh2.rb:8:in `open' 
     from ./ssh2.rb:8 
फ़ाइल

सही ढंग से प्राप्त किया जाता है, मैं रिश्तेदार पथ का उपयोग कर रहा, जैसा कि मैंने निर्देशिका में बैठा हूँ यह वही है मैं अब तक किया है आदि के तहत/(नहीं/आदि, मैं इसे एक स्क्रिप्टिंग निर्देशिका से बाहर चला रहा हूं जहां मैं फाइल को उपनिर्देशिका में रखता हूं आदि)

+4

दूसरों के कहने के अलावा, मैं बस यह इंगित करना चाहता हूं कि रुबी में लूप का अधिक उपयोग नहीं किया जाता है। 'प्रत्येक' विधि का प्रयोग अक्सर किया जाता है। –

+0

स्ट्रिंग से व्हाइटस्पेस को बंद करने के लिए एक line.strip करें। इस अनुलग्नक – Matt

+0

के साथ नीचे मेरा उत्तर अपडेट किया गया है नई लाइन से छुटकारा पाने के लिए 'chomp' जोड़ें। मैं अपना जवाब अपडेट करूंगा। – Telemachus

उत्तर

25
File.open("/etc/SERVER_LIST", "r") do |file_handle| 
    file_handle.each_line do |server| 
    # do stuff to server here 
    end 
end 

पहली पंक्ति पढ़ने के लिए फ़ाइल को खोलता है और तुरंत एक ब्लॉक में चला जाता है। (ब्लॉक do और end के बीच कोड है। आप केवल { और } के साथ ब्लॉक को घेर सकते हैं।अंगूठे का नियम do..end मल्टी-लाइन ब्लॉक और {...} एकल लाइन ब्लॉक के लिए है।) ब्लॉक बहुत रूबी में आम हैं। while या for लूप से कहीं अधिक मूर्खतापूर्ण।) open पर कॉल स्वचालित रूप से फ़ाइल हैंडल प्राप्त करता है, और आप इसे पाइप में एक नाम देते हैं।

एक बार जब आप इसे पकड़ लेंगे, तो बोलने के लिए, आप each_line पर कॉल कर सकते हैं, और इस पर पुनरावृत्त हो जैसे कि यह एक सरणी थी। दोबारा, प्रत्येक पुनरावृत्ति स्वचालित रूप से आपको एक रेखा से गुजरती है, जिसे आप पाइप में जो पसंद करते हैं उसे कॉल करते हैं।

इस विधि के बारे में अच्छी बात यह है कि यह आपके साथ समाप्त होने पर फ़ाइल को बंद करने की परेशानी बचाता है। जब आप बाहरी ब्लॉक छोड़ते हैं तो इस तरह से खोला गया फ़ाइल स्वचालित रूप से बंद हो जाएगा।

एक और बात: फ़ाइल लगभग निश्चित रूप से /etc/SERVER_LIST नामित है। फ़ाइल सिस्टम की जड़ को इंगित करने के लिए आपको प्रारंभिक / की आवश्यकता है (जब तक कि आप जानबूझकर फ़ाइल के पथ के लिए सापेक्ष मूल्य का उपयोग नहीं कर रहे हैं, जो मुझे संदेह है)। वह अकेला ही आपको फ़ाइल को खोलने से रोक सकता है।

नई त्रुटि के लिए अद्यतन: Net::SSH नई लाइन पर बारफिंग कर रहा है। आप जहां इस है:

Net::SSH.start(line, 'andex') do |ssh| 

यह इस बनाना:

Net::SSH.start(line.chomp, 'andex') do |ssh| 

chomp विधि एक स्ट्रिंग से किसी भी अंतिम न्यू लाइन चरित्र निकाल देता है।

+0

हूप्स .. वास्तव में सही ढंग से प्रारूपित नहीं किया गया था। मुझे मूल पोस्ट अपडेट करने दें। – awojo

+0

मूल पोस्ट को अपडेट किया गया, मुझे लगता है कि आपके द्वारा पोस्ट की गई हर विधि के साथ मुझे एक ही त्रुटि मिल रही है .. – awojo

+0

क्या फ़ाइल की सभी सामग्री मेमोरी में लोड हो जाएगी? या एक समय में केवल एक लाइन? यानी यदि आप 80 जीबी सीएसवी रखते हैं तो क्या आप इस कोड का उपयोग कर सकते हैं? –

4

फ़ाइल का ऑनलाइन पुनरावृत्ति करते समय सबसे आम निर्माण मैं देखता हूं :

File.open("etc/SERVER_LIST") do |f| 
    f.each_line do |line| 
     # do something here 
    end 
end 

कुछ अधिक सामान्य रूबी की जानकारी के साथ ऊपर पर विस्तार करने के लिए ... इस वाक्य रचना के बराबर है: | f

File.open("etc/SERVER_LIST") { |f| 
    f.each_line { |line| 
     # do something here 
    } 
} 

जब मैं पहली बार रूबी के लिए पेश किया गया था, मुझे नहीं पता क्या था | और | लाइन | वाक्यविन्यास मतलब था। मुझे पता था कि इसका उपयोग कब किया जाए, और यह कैसे काम किया, लेकिन क्यों नहीं कि वे वाक्यविन्यास चुनते हैं। यह मेरी राय में रूबी के बारे में जादुई चीजों में से एक है। उपरोक्त सरल वाक्यविन्यास वास्तव में आपकी नाक के नीचे एक बहुत ही उन्नत प्रोग्रामिंग अवधारणा को छुपा रहा है। "डू"/"एंड" या {} के अंदर घोंसला वाला कोड ब्लॉक कहा जाता है। और आप इसे एक अज्ञात फ़ंक्शन या लैम्ब्डा पर विचार कर सकते हैं। | एफ | और | लाइन | वाक्यविन्यास वास्तव में निष्पादन माता-पिता द्वारा कोड के ब्लॉक में पारित पैरामीटर को हैंडल है।

File.open() के मामले में, अनाम फ़ंक्शन एक एकल तर्क लेता है, जो अंडरलिंग फ़ाइल IO ऑब्जेक्ट के लिए हैंडल है।

प्रत्येक_लाइन के मामले में, यह एक इंटरैटर फ़ंक्शन है जिसे प्रत्येक पंक्ति के लिए एक बार बुलाया जाता है। | लाइन | केवल उस डेटा के लिए एक परिवर्तनीय हैंडल है जो फ़ंक्शन के प्रत्येक पुनरावृत्ति के साथ पारित हो जाता है।

ओह, और File.open के साथ/अंत के बारे में एक अच्छी बात यह है कि यह अंत में फ़ाइल को स्वचालित रूप से बंद कर देता है।

संपादित करें:

त्रुटि तुम अब हो रही है पता चलता है SSH कॉल स्ट्रिंग के अंत में अतिरिक्त व्हाइट (newline) की सराहना नहीं करता है। इसे ठीक करने के लिए, बस एक

Net::SSH.start(line.strip, 'andex') do |ssh| 
end 
+0

अच्छा स्पष्टीकरण। मैं बस इतना जोड़ूंगा कि हालांकि 'प्रत्येक_लाइन' अधिक स्पष्ट है (जैसा कि आप इसे फ़ाइल ऑब्जेक्ट पर कॉल कर रहे हैं), नियमित' प्रत्येक 'भी काम करता है। मैं इसका उपयोग करता हूं - कम टाइपिंग और यह मुझे याद दिलाता है कि फाइल को लाइनों की सरणी की तरह माना जा सकता है। – Telemachus

+1

असल में, एक और बात: यह एक सम्मेलन नियम नहीं है लेकिन '{...}' बहु-रेखा ब्लॉक के लिए वास्तव में मेरे लिए गलत लगता है। – Telemachus

+0

@Telemachus हाँ, सहमत - multilines के लिए/अंत करें और {} एकल लाइन के लिए अनिश्चित मानक प्रतीत होता है। मल्टीलाइन ब्रैकेट की तुलना में एक सिंगल लाइन डू/एंड भी बदसूरत है! – Matt

11

उपयोग File.foreach कार्य करें:

require 'net/ssh' 

File.foreach('etc/SERVER_LIST', "\n") do |line| 
     Net::SSH.start(line, 'andex') do |ssh| 
      result = ssh.exec!("ls -l") 
      puts result 
     end 
end 
1

एक फ़ाइल से लाइनों में पढ़ना एक आम ऑपरेशन है, और रूबी ऐसा करने के लिए एक आसान तरीका है:

servers = File.readlines('/etc/SERVER_LIST') 

readlines विधि फ़ाइल खुलेगी, एक सरणी में फ़ाइल को पढ़ने, और उसे बंद आपके लिए फ़ाइल (इसलिए आपको उसमें से किसी के बारे में चिंता करने की ज़रूरत नहीं है)। परिवर्तनीय servers तारों की एक सरणी होगी; प्रत्येक स्ट्रिंग फ़ाइल से एक लाइन होगी। आप Array::each विधि का उपयोग इस सरणी के माध्यम से पुन: प्रयास करने के लिए कर सकते हैं और आपके पास पहले से मौजूद कोड का उपयोग कर सकते हैं। इस प्रयास करें:

servers = File.readlines('/etc/SERVER_LIST') 
servers.each {|s| 
    Net::SSH.start(s, 'andex') {|ssh| puts ssh.exec!("ls -l") } 
} 
+2

आप * यह कर सकते हैं, लेकिन मैं नहीं करूँगा। सबसे पहले, अगर फ़ाइल बहुत बड़ी है, तो 'रीडलाइन' काफी मेमोरी हिट होगी। दूसरा, इस तरह के मामले में, 'सर्वर' जैसी सरणी बनाने की कोई आवश्यकता नहीं है। बस फ़ाइल को ब्लॉक करें (जैसा कि हम में से कुछ अन्य उत्तरों में करते हैं) और लाइनों पर काम करते समय उन्हें प्राप्त करते हैं। कोई स्थायी सरणी की आवश्यकता नहीं है। – Telemachus

+0

@ टेलीमाचस- चूंकि उन्होंने उल्लेख किया कि वह रूबी नौसिखिया थे, मैंने अभी उस विधि को चुना है जो पढ़ने और समझने के लिए सबसे सरल था (केवल एक ब्लॉक, फ़ाइल को खुले/बंद की गई देखभाल को पारदर्शी रूप से)। हालांकि, आप सही हैं, कि यह किसी भी प्रोसेसिंग से पहले पूरी फाइल में पढ़ेगा। ओपी द्वारा उल्लिखित एक साधारण सूची की तुलना में कुछ भी अधिक पर, यह आसानी से एक प्रदर्शन हॉग हो सकता है। – bta

+1

ओपी रिमोट ऑपरेशंस करने के लिए नेट :: एसएसएच का उपयोग कर रहा है, इसलिए पूरी फाइल पढ़ने की याद में लागत चिंता का विषय नहीं है: प्रक्रिया में पूरे दिन लेने के लिए पर्याप्त फ़ाइल मेमोरी में आराम से फिट होगी। –

1

मुझे लगता है कि यह आप in 'initialize': newline at the end of hostname (SocketError) त्रुटि के लिए क्या चाहते है:

Net::SSH.start(line.chomp, 'andex')

each_line विधि "\ n" भी शामिल है, और Chomp निकाल देंगे।

+0

यह काम किया !! धन्यवाद – awojo