रूबी में सिस्टम का आउटपुट प्राप्त करना () कॉल


309

अगर मैं रूबी में कर्नेल # सिस्टम का उपयोग करके एक कमांड को कॉल करता हूं, तो मुझे इसका आउटपुट कैसे मिलेगा?

system("ls")


यह एक बहुत ही धागा है, धन्यवाद। कमांड चलाने और प्रतिक्रिया प्राप्त करने का वर्ग नमूना कोड में बहुत अच्छा है।
ylluminate

3
भविष्य के googler के लिए। यदि आप अन्य सिस्टम कमांड कॉल और उनके अंतर के बारे में सीखना चाहते हैं, तो यह एसओ उत्तर देखें
उज्बोन

जवाबों:


347

मैं अव्यवस्था के जवाब को थोड़ा विस्तार और स्पष्ट करना चाहूंगा ।

यदि आप अपने कमांड को बैकटिक्स के साथ घेरते हैं, तो आपको (स्पष्ट रूप से) कॉल सिस्टम () की आवश्यकता नहीं है। बैकटिक्स कमांड को निष्पादित करता है और आउटपुट को एक स्ट्रिंग के रूप में लौटाता है। फिर आप वैरिएबल को मान असाइन कर सकते हैं जैसे:

output = `ls`
p output

या

printf output # escapes newline chars

4
क्या होगा अगर मुझे मेरी कमांड के हिस्से के रूप में एक चर देने की आवश्यकता है? यही है, सिस्टम ("ls" + फ़ाइलनाम) जैसा कुछ क्या होगा जब बैकटिक्स का उपयोग किया जाना है?
विजय देव २ Dev

47
आप अभिव्यक्ति का मूल्यांकन वैसे ही कर सकते हैं जैसे आप नियमित स्ट्रिंग्स के साथ करेंगे ls #{filename}:।
क्रेग वॉकर

36
यह उत्तर उचित नहीं है: यह असंगत उपयोगकर्ता इनपुट की नई समस्या का परिचय देता है।
डॉगवेदर

4
@ डॉगवेदर: यह सच हो सकता है, लेकिन क्या यह किसी भी अन्य तरीकों से अलग है?
क्रेग वॉकर

20
अगर आप अपने कमांड के अंत में सिर्फ 2> & 1 लगाना चाहते हैं जैसे उत्पादन =command 2>&1
micred

243

ध्यान रखें कि सब समाधान है जहाँ आप एक स्ट्रिंग के लिए उपयोगकर्ता प्रदान की मूल्यों से युक्त पारित हो system, %x[]आदि असुरक्षित कर रहे हैं! असुरक्षित का वास्तव में मतलब है: उपयोगकर्ता संदर्भ में और कार्यक्रम की सभी अनुमतियों को चलाने के लिए कोड को ट्रिगर कर सकता है।

जहां तक ​​मैं केवल कह सकता हूं systemऔर Open3.popen3रूबी 1.8 में एक सुरक्षित / भागने वाला संस्करण प्रदान करता हूं । रूबी 1.9 में IO::popenभी एक सरणी को स्वीकार करता है।

इन कॉल में से किसी एक के रूप में बस हर विकल्प और तर्क को पास करें।

यदि आपको न केवल बाहर निकलने की स्थिति की आवश्यकता है, बल्कि परिणाम भी है जिसका आप शायद उपयोग करना चाहते हैं Open3.popen3:

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
stdout.gets(nil)
stdout.close
stderr.gets(nil)
stderr.close
exit_code = wait_thr.value

ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।

यहां अधिक जानकारी: रूबी में सैनिटरी शेल कमांड या सिस्टम कॉल


26
यह एकमात्र ऐसा उत्तर है जो वास्तव में प्रश्न का उत्तर देता है और नए (बिना इनपुट) के परिचय के बिना समस्या को हल करता है।
डॉगवेदर

2
धन्यवाद! यह उस तरह का जवाब है जिसकी मैं उम्मीद कर रहा था। एक सुधार: getsकॉल को तर्क पास करना चाहिए nil, अन्यथा हमें आउटपुट की पहली पंक्ति मिलती है। इसलिए उदा stdout.gets(nil)
ग्रेग प्राइस

3
स्टड, स्टडआउट और स्टेडर को गैर-ब्लॉक रूप में स्पष्ट रूप से बंद किया जाना चाहिए ।
यारिन

क्या किसी को पता है कि रूबी 2.0 या 2.1 में कुछ बदला है? संपादन या टिप्पणी की सराहना की जाएगी ;-)
शमौन Hürlimann

1
मुझे लगता है कि चारों ओर चर्चा Open3.popen3एक बड़ी समस्या याद आ रही है: यदि आपके पास एक उपप्रकार है जो एक पाइप को पकड़ने की तुलना में स्टडआउट करने के लिए अधिक डेटा लिखता है, तो उपप्रोसेस में निलंबित हो जाता है stderr.writeऔर आपका प्रोग्राम अंदर फंस जाता है stdout.gets(nil)
हैगेलो

165

केवल रिकॉर्ड के लिए, यदि आप दोनों (आउटपुट और संचालन परिणाम) चाहते हैं, तो आप कर सकते हैं:

output=`ls no_existing_file` ;  result=$?.success?

4
यही वह है जिसकी तलाश में मैं हूं। धन्यवाद।
jdl

12
यह केवल stdout को कैप्चर करता है, और Stderr कंसोल पर जाता है। output=`ls no_existing_file 2>&1`; result=$?.success?
Stderr

8
यह उत्तर असुरक्षित है और इसका उपयोग नहीं किया जाना चाहिए - यदि कमांड कुछ भी है लेकिन एक स्थिर है, तो बैकटिक सिंटैक्स में बग होने की संभावना है, संभवतः एक सुरक्षा भेद्यता। (और यहां तक ​​कि अगर यह एक निरंतर है, तो यह संभवतः किसी को इसे गैर-स्थिरांक के लिए बाद में उपयोग करने और बग पैदा करने का कारण होगा।) एक सही समाधान के लिए साइमन हुरिलमैन का जवाब देखें ।
ग्रेग मूल्य

23
उपयोगकर्ता इनपुट से बचने की आवश्यकता के बारे में समझने के लिए ग्रेग प्राइस के लिए यश, लेकिन यह जवाब सही नहीं है क्योंकि लिखित असुरक्षित है। उल्लिखित ओपन 3 विधि अधिक जटिल है और अधिक निर्भरता का परिचय देती है, और यह तर्क कि कोई "बाद में एक गैर-निरंतर के लिए इसका उपयोग करेगा" एक स्ट्रोमैन है। यह सच है, आप शायद उनका उपयोग किसी Rails ऐप में नहीं करेंगे, लेकिन बिना सिलेण्डर यूजर इनपुट की संभावना वाले एक साधारण सिस्टम यूटिलिटी स्क्रिप्ट के लिए, backticks पूरी तरह से ठीक हैं और किसी को भी उनका उपयोग करने के बारे में बुरा महसूस नहीं कराया जाना चाहिए।
सब्म

69

इसका सही और सुरक्षित तरीके से उपयोग करने का सीधा तरीका है Open3.capture2() , Open3.capture2e()या Open3.capture3()

माणिक की पीठ और उसका उपयोग करना %x उपनाम का उपयोग किसी भी डेटा के साथ उपयोग किए जाने पर किसी भी सुरक्षा को सुरक्षित नहीं कर रहे हैं । यह है खतरनाक , सीधे और सरल शब्दों:

untrusted = "; date; echo"
out = `echo #{untrusted}`                              # BAD

untrusted = '"; date; echo"'
out = `echo "#{untrusted}"`                            # BAD

untrusted = "'; date; echo'"
out = `echo '#{untrusted}'`                            # BAD

systemसमारोह, इसके विपरीत में, ठीक से तर्क निकल जाता है अगर सही ढंग से इस्तेमाल किया :

ret = system "echo #{untrusted}"                       # BAD
ret = system 'echo', untrusted                         # good

परेशानी यह है कि यह आउटपुट के बजाय निकास कोड लौटाता है, और बाद को कैप्चर करना जटिल और गड़बड़ है।

इस सूत्र में अब तक के सबसे अच्छे उत्तर में Open3 का उल्लेख है, लेकिन उन कार्यों का नहीं जो कार्य के लिए सबसे उपयुक्त हैं। Open3.capture2, capture2eऔर capture3काम की तरह system, लेकिन दो या तीन तर्क देता है:

out, err, st = Open3.capture3("echo #{untrusted}")     # BAD
out, err, st = Open3.capture3('echo', untrusted)       # good
out_err, st  = Open3.capture2e('echo', untrusted)      # good
out, st      = Open3.capture2('echo', untrusted)       # good
p st.exitstatus

एक और उल्लेख IO.popen()। वाक्य रचना इस अर्थ में अनाड़ी हो सकती है कि उसे इनपुट के रूप में एक सरणी चाहिए, लेकिन यह भी काम करता है:

out = IO.popen(['echo', untrusted]).read               # good

सुविधा के लिए, आप Open3.capture3()एक फ़ंक्शन में लपेट सकते हैं , उदाहरण के लिए:

#
# Returns stdout on success, false on failure, nil on error
#
def syscall(*cmd)
  begin
    stdout, stderr, status = Open3.capture3(*cmd)
    status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol
  rescue
  end
end

उदाहरण:

p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

निम्नलिखित पैदावार:

nil
nil
false
false
/usr/bin/which         <— stdout from system('which', 'which')
true                   <- p system('which', 'which')
"/usr/bin/which"       <- p syscall('which', 'which')

2
यह सही जवाब है। यह सबसे अधिक जानकारीपूर्ण भी है। केवल एक चीज गायब है जो एसटीडी को बंद करने के बारे में चेतावनी है। यह अन्य टिप्पणी देखें : require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read } ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।
पीटर एच। बोलिंग

@ पीटरएच.बोलिंग: सबसे अच्छी तरह से मैं अवगत हूं capture2, capture2eऔर अपने आप capture3ही उन्हें एसटीडी * भी बंद कर देता हूं। (बहुत कम से कम, मैं अपने अंत में समस्या में कभी नहीं भागा।)
डेनिस डे बर्नार्डी

ब्लॉक फॉर्म का उपयोग किए बिना किसी कोडबेस के लिए यह जानने का कोई तरीका नहीं है कि कब कुछ बंद होना चाहिए, इसलिए मुझे अत्यधिक संदेह है कि उन्हें बंद किया जा रहा है। आप शायद एक समस्या में कभी नहीं भागे क्योंकि उन्हें बंद नहीं करने से एक अल्पकालिक प्रक्रिया में समस्या पैदा नहीं होगी, और यदि आप एक लंबे समय से चलने वाली प्रक्रिया को पर्याप्त रूप से फिर से शुरू करते हैं, तो आदर्श वाक्य तब तक दिखाई नहीं देगा जब तक कि आप एसटीडी खोल नहीं रहे हैं * में एक लूप। लिनक्स में एक उच्च फ़ाइल डिस्क्रिप्टर की सीमा है, जिसे आप हिट कर सकते हैं, लेकिन जब तक आप इसे नहीं मारेंगे तब तक आप "बग" नहीं देखेंगे।
पीटर एच। बोलिंग

2
@ पीटरएच.बोलिंग: नहीं नहीं, स्रोत कोड देखें। फ़ंक्शंस बस रैपर हैं Open3#popen2, popen2eऔर popen3एक पूर्वनिर्धारित ब्लॉक के साथ: रूबी- doc.org/stdlib-2.1.1/libdoc/open3/rdoc/…
डेनिस डे बर्नार्डी

1
@ डेनिस डे बरनार्डी शायद आपने याद किया कि मैं एक ही वर्ग के दस्तावेज से जुड़ा हुआ था (रूबी 2.0.0 के लिए यद्यपि, और एक अलग विधि। रुबी- doc.org/stdlib-2.1.1/libdoc/open3/rdoc/… उदाहरण से : `` `stdin, stdout, stderr, Wait_thr = Open3.popen3 ([env, cmd ... [, opts]) pid = Wait_thr [: pid] # प्रारंभ प्रक्रिया का # pid ... stdin.close # stdin , stdout और stderr इस रूप में स्पष्ट रूप से बंद कर दिया जाना चाहिए stdout.close stderr.close `` `मैं सिर्फ प्रलेखन के हवाले किया गया था" # stdin, stdout और stderr इस रूप में स्पष्ट रूप से बंद किया जाना चाहिए।
पीटर एच Boling

61

आप सिस्टम () या% x [] का उपयोग कर सकते हैं कि आपको किस तरह के परिणाम की आवश्यकता है।

सिस्टम () सही है अगर कमांड पाया गया था और सफलतापूर्वक चला, अन्यथा झूठ।

>> s = system 'uptime'
10:56  up 3 days, 23:10, 2 users, load averages: 0.17 0.17 0.14
=> true
>> s.class
=> TrueClass
>> $?.class
=> Process::Status

दूसरी ओर% x [..] कमांड के परिणाम को स्ट्रिंग के रूप में बचाता है:

>> result = %x[uptime]
=> "13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> p result 
"13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> result.class
=> String

जे फील्ड्स द्वारा Th ब्लॉग पोस्ट प्रणाली, निष्पादन और% x [..] का उपयोग करने के बीच के अंतर को विस्तार से बताता है।


2
% X [] का उपयोग करने की टिप के लिए धन्यवाद। यह सिर्फ एक समस्या को हल करता है, जहां मैंने मैक ओएस एक्स में एक रूबी स्क्रिप्ट में बैक टिक का उपयोग किया था। जब सिग्विन के साथ विंडोज मशीन पर एक ही स्क्रिप्ट चला रहा था, तो यह बैक टिक के कारण विफल हो गया, लेकिन% x [] के साथ काम किया।
हेनरिक वार्न

22

यदि आपको तर्क से बचने की आवश्यकता है, तो रूबी 1.9 IO.popen में भी एक सरणी स्वीकार करता है:

p IO.popen(["echo", "it's escaped"]).read

पहले के संस्करणों में आप Open3.popen3 का उपयोग कर सकते हैं :

require "open3"

Open3.popen3("echo", "it's escaped") { |i, o| p o.read }

यदि आपको स्टड पास करने की आवश्यकता है, तो यह 1.9 और 1.8 दोनों में काम करना चाहिए:

out = IO.popen("xxd -p", "r+") { |io|
    io.print "xyz"
    io.close_write
    io.read.chomp
}
p out # "78797a"

धन्यवाद! यह पूर्ण है।
ग्रेग प्राइस

21

आप backticks का उपयोग करें:

`ls`

5
बैकटिक्स टर्मिनल पर आउटपुट का उत्पादन नहीं करते हैं।
मेई

3
यह stderr का उत्पादन नहीं करता है लेकिन यह stdout देता है।
निकोलय कोंडरांटेंको

1
यह stdout या stderr को नहीं लिखता है। आइए इस उदाहरण का प्रयास करें ruby -e '%x{ls}'- ध्यान दें, कोई आउटपुट नहीं। ( %x{}
फी बैकटिक्स के

यह बहुत अच्छा काम किया। उपयोग shकरने से आउटपुट कंसोल (यानी STDOUT) के साथ-साथ इसे वापस लौटा देगा। यह नहीं है
जोशुआ पिन्टर

19

एक और तरीका है:

f = open("|ls")
foo = f.read()

ध्यान दें कि खुले में "ls" से पहले "पाइप" वर्ण है। इसका उपयोग प्रोग्राम्स के इनपुट में डेटा को फीड करने के साथ-साथ इसके स्टैंडर्ड आउटपुट को पढ़ने के लिए भी किया जा सकता है।


बस इस प्रयोग किया जाता है क्रम json और नहीं की 'सही' आधिकारिक वापसी मान को पढ़ने के लिए में एक एडब्ल्यूएस CLI आदेश से मानक आउटपुट को पढ़ने के लिए
kraftydevil

14

मैंने पाया कि यदि आपको रिटर्न वैल्यू की आवश्यकता हो तो निम्नलिखित उपयोगी है:

result = %x[ls]
puts result

मैं विशेष रूप से अपनी मशीन पर सभी जावा प्रक्रियाओं के ग्रिड को सूचीबद्ध करना चाहता था, और इसका उपयोग करता था:

ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]

यह एक महान समाधान है।
रॉनन लूनर

13

जैसा कि साइमन हर्लीमन्न ने पहले ही समझाया था , ओपन 3 बैकटिक्स आदि से अधिक सुरक्षित है।

require 'open3'
output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }

ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।


9

बैकटिक्स या पॉपेन का उपयोग करते समय अक्सर आप वास्तव में क्या चाहते हैं, यह वास्तव में पूछे गए प्रश्न का उत्तर नहीं देता है। systemउत्पादन पर कब्जा करने के लिए वैध कारण हो सकते हैं (शायद स्वचालित परीक्षण के लिए)। एक छोटे से Googling ने एक उत्तर दिया मुझे लगा कि मैं यहां दूसरों के लाभ के लिए पोस्ट करूंगा।

चूँकि मुझे अपने उदाहरण के परीक्षण के लिए इसकी आवश्यकता थी, मानक आउटपुट पर कब्जा करने के लिए ब्लॉक सेटअप का उपयोग करता है क्योंकि वास्तविक systemकॉल को परीक्षण किए जा रहे कोड में दफन किया जाता है:

require 'tempfile'

def capture_stdout
  stdout = $stdout.dup
  Tempfile.open 'stdout-redirect' do |temp|
    $stdout.reopen temp.path, 'w+'
    yield if block_given?
    $stdout.reopen stdout
    temp.read
  end
end

यह विधि वास्तविक डेटा को संग्रहीत करने के लिए दिए गए ब्लॉक का उपयोग करके किसी भी ब्लॉक में किसी भी आउटपुट को पकड़ती है। उदाहरण का उपयोग:

captured_content = capture_stdout do
  system 'echo foo'
end
puts captured_content

आप systemकॉल को आंतरिक रूप से कॉल करने वाली किसी भी चीज़ से बदल सकते हैं systemstderrयदि आप चाहते थे तो कैप्चर करने के लिए आप एक समान विधि का उपयोग भी कर सकते थे।


8

यदि आप चाहते हैं कि आउटपुट का उपयोग करके किसी फ़ाइल में रीडायरेक्ट किया जाए Kernel#system , तो आप इस तरह से वर्णनकर्ताओं को संशोधित कर सकते हैं:

परिशिष्ट मोड में एक फ़ाइल (/ tmp / log) के लिए stdout और stderr को पुनर्निर्देशित करें:

system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])

लंबे समय तक चलने वाली कमांड के लिए, यह आउटपुट को रियल टाइम में स्टोर करेगा। आप आईओ का उपयोग कर आउटपुट को स्टोर भी कर सकते हैं और कर्नेल # सिस्टम से इसे रीडायरेक्ट कर सकते हैं।



0

मुझे यह यहाँ नहीं मिला इसलिए इसे जोड़कर, मुझे कुछ मुद्दों पर पूर्ण आउटपुट मिल रहा था।

यदि आप backtick का उपयोग करके STDERR पर कब्जा करना चाहते हैं तो आप STDERR को STDOUT में पुनर्निर्देशित कर सकते हैं।

आउटपुट = `grep होस्ट / निजी / आदि / * 2> और 1`

स्रोत: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-rubin


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.