अगर मैं रूबी में कर्नेल # सिस्टम का उपयोग करके एक कमांड को कॉल करता हूं, तो मुझे इसका आउटपुट कैसे मिलेगा?
system("ls")
अगर मैं रूबी में कर्नेल # सिस्टम का उपयोग करके एक कमांड को कॉल करता हूं, तो मुझे इसका आउटपुट कैसे मिलेगा?
system("ls")
जवाबों:
मैं अव्यवस्था के जवाब को थोड़ा विस्तार और स्पष्ट करना चाहूंगा ।
यदि आप अपने कमांड को बैकटिक्स के साथ घेरते हैं, तो आपको (स्पष्ट रूप से) कॉल सिस्टम () की आवश्यकता नहीं है। बैकटिक्स कमांड को निष्पादित करता है और आउटपुट को एक स्ट्रिंग के रूप में लौटाता है। फिर आप वैरिएबल को मान असाइन कर सकते हैं जैसे:
output = `ls`
p output
या
printf output # escapes newline chars
ls #{filename}
:।
command 2>&1
ध्यान रखें कि सब समाधान है जहाँ आप एक स्ट्रिंग के लिए उपयोगकर्ता प्रदान की मूल्यों से युक्त पारित हो 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
ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।
यहां अधिक जानकारी: रूबी में सैनिटरी शेल कमांड या सिस्टम कॉल
gets
कॉल को तर्क पास करना चाहिए nil
, अन्यथा हमें आउटपुट की पहली पंक्ति मिलती है। इसलिए उदा stdout.gets(nil)
।
Open3.popen3
एक बड़ी समस्या याद आ रही है: यदि आपके पास एक उपप्रकार है जो एक पाइप को पकड़ने की तुलना में स्टडआउट करने के लिए अधिक डेटा लिखता है, तो उपप्रोसेस में निलंबित हो जाता है stderr.write
और आपका प्रोग्राम अंदर फंस जाता है stdout.gets(nil)
।
केवल रिकॉर्ड के लिए, यदि आप दोनों (आउटपुट और संचालन परिणाम) चाहते हैं, तो आप कर सकते हैं:
output=`ls no_existing_file` ; result=$?.success?
output=`ls no_existing_file 2>&1`; result=$?.success?
इसका सही और सुरक्षित तरीके से उपयोग करने का सीधा तरीका है 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')
require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।
capture2
, capture2e
और अपने आप capture3
ही उन्हें एसटीडी * भी बंद कर देता हूं। (बहुत कम से कम, मैं अपने अंत में समस्या में कभी नहीं भागा।)
Open3#popen2
, popen2e
और popen3
एक पूर्वनिर्धारित ब्लॉक के साथ: रूबी- doc.org/stdlib-2.1.1/libdoc/open3/rdoc/…
आप सिस्टम () या% 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 [..] का उपयोग करने के बीच के अंतर को विस्तार से बताता है।
यदि आपको तर्क से बचने की आवश्यकता है, तो रूबी 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"
आप backticks का उपयोग करें:
`ls`
ruby -e '%x{ls}'
- ध्यान दें, कोई आउटपुट नहीं। ( %x{}
sh
करने से आउटपुट कंसोल (यानी STDOUT) के साथ-साथ इसे वापस लौटा देगा। यह नहीं है
एक और तरीका है:
f = open("|ls")
foo = f.read()
ध्यान दें कि खुले में "ls" से पहले "पाइप" वर्ण है। इसका उपयोग प्रोग्राम्स के इनपुट में डेटा को फीड करने के साथ-साथ इसके स्टैंडर्ड आउटपुट को पढ़ने के लिए भी किया जा सकता है।
मैंने पाया कि यदि आपको रिटर्न वैल्यू की आवश्यकता हो तो निम्नलिखित उपयोगी है:
result = %x[ls]
puts result
मैं विशेष रूप से अपनी मशीन पर सभी जावा प्रक्रियाओं के ग्रिड को सूचीबद्ध करना चाहता था, और इसका उपयोग करता था:
ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]
जैसा कि साइमन हर्लीमन्न ने पहले ही समझाया था , ओपन 3 बैकटिक्स आदि से अधिक सुरक्षित है।
require 'open3'
output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
ध्यान दें कि ब्लॉक फॉर्म ऑटो-स्टड, स्टडआउट और स्टेडर- को बंद कर देगा अन्यथा उन्हें स्पष्ट रूप से बंद करना होगा ।
बैकटिक्स या पॉपेन का उपयोग करते समय अक्सर आप वास्तव में क्या चाहते हैं, यह वास्तव में पूछे गए प्रश्न का उत्तर नहीं देता है। 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
कॉल को आंतरिक रूप से कॉल करने वाली किसी भी चीज़ से बदल सकते हैं system
। stderr
यदि आप चाहते थे तो कैप्चर करने के लिए आप एक समान विधि का उपयोग भी कर सकते थे।
यदि आप चाहते हैं कि आउटपुट का उपयोग करके किसी फ़ाइल में रीडायरेक्ट किया जाए Kernel#system
, तो आप इस तरह से वर्णनकर्ताओं को संशोधित कर सकते हैं:
परिशिष्ट मोड में एक फ़ाइल (/ tmp / log) के लिए stdout और stderr को पुनर्निर्देशित करें:
system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])
लंबे समय तक चलने वाली कमांड के लिए, यह आउटपुट को रियल टाइम में स्टोर करेगा। आप आईओ का उपयोग कर आउटपुट को स्टोर भी कर सकते हैं और कर्नेल # सिस्टम से इसे रीडायरेक्ट कर सकते हैं।
एक सीधी प्रणाली (...) प्रतिस्थापन के रूप में आप Open3.popen3 (...) का उपयोग कर सकते हैं
आगे की चर्चा: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
मुझे यह यहाँ नहीं मिला इसलिए इसे जोड़कर, मुझे कुछ मुद्दों पर पूर्ण आउटपुट मिल रहा था।
यदि आप backtick का उपयोग करके STDERR पर कब्जा करना चाहते हैं तो आप STDERR को STDOUT में पुनर्निर्देशित कर सकते हैं।
आउटपुट = `grep होस्ट / निजी / आदि / * 2> और 1`
स्रोत: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-rubin
puts `date`
puts $?
Mon Mar 7 19:01:15 PST 2016
pid 13093 exit 0