আমি যদি রুবিতে কার্নেল # সিস্টেম ব্যবহার করে একটি কমান্ড কল করি, তবে আমি কীভাবে এর আউটপুট পেতে পারি?
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 মধ্যে একটি নিরাপদ / পলায়নপর বৈকল্পিক প্রদান না। রুবিতে 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
সমস্যাটি হ'ল এটি আউটপুটটির পরিবর্তে প্রস্থান কোডটি ফেরত দেয় এবং পরবর্তীটিকে ক্যাপচার করা গোলাকার এবং অগোছালো।
এই থ্রেডের সেরা উত্তরটি এখন পর্যন্ত ওপেন 3-এর উল্লেখ করেছে, তবে কার্যের জন্য উপযুক্ত উপযুক্ত ফাংশনগুলি নয়। 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 }
নোট ব্লক গঠন করবে স্বয়ংক্রিয় ঘনিষ্ঠ stdin, stdout- এ এবং stderr- অন্যথায় তারা হতে চাই যে স্পষ্টভাবে বন্ধ ।
capture2
, capture2e
এবং capture3
এছাড়াও ঘনিষ্ঠ তাদের std * স্বয়ংক্রিয়ভাবে s। (খুব কমপক্ষে, আমি কখনই আমার শেষ পর্যন্ত সমস্যার দিকে
Open3#popen2
, popen2e
এবং popen3
একটি পূর্বনির্ধারিত ব্লক সহ: রুবি- ডক.আর.এস.সি.ডি.লি.বি.২.১.১
আপনার কী ধরণের ফলাফলের প্রয়োজন তা নির্ভর করে আপনি সিস্টেম () বা% 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
ম ব্লগ পোস্ট জে ক্ষেত্রসমূহ দ্বারা [..] সিস্টেম ব্যবহার মধ্যে পার্থক্য বিস্তারিতভাবে ব্যাখ্যা করে, Exec এবং% এক্স।
আপনার যদি যুক্তিগুলি থেকে বাঁচার দরকার হয় তবে রুবি ১.৯-এ আইও.পপেন একটি অ্যারে গ্রহণ করে:
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"
আপনি ব্যাকটিক্স ব্যবহার:
`ls`
ruby -e '%x{ls}'
- দ্রষ্টব্য, কোনও আউটপুট নেই। (FYI %x{}
ব্যাকটিক সমতূল্য।)
sh
ফলে আউটপুটটি কনসোল (যেমন STDOUT) তে প্রতিস্থাপিত হবে এবং ফিরে আসবে। এটা হয় না।
আমি খুঁজেছি যে আপনার যদি ফেরতের মান প্রয়োজন হয় তবে নিম্নলিখিতগুলি কার্যকর হয়:
result = %x[ls]
puts result
আমি বিশেষভাবে আমার মেশিনে সমস্ত জাভা প্রক্রিয়াগুলির পিডগুলি তালিকাবদ্ধ করতে চেয়েছি এবং এটি ব্যবহার করেছি:
ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]
হিসাবে সাইমন Hürlimann ইতিমধ্যে ব্যাখ্যা , Open3 ব্যাকটিক ইত্যাদি চেয়ে নিরাপদ
require 'open3'
output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
মনে রাখবেন যে ব্লক ফর্মটি স্টিডিন, স্টডআউট এবং স্ট্ডারকে স্বয়ংক্রিয়ভাবে বন্ধ করবে - অন্যথায় তারা স্পষ্টভাবে বন্ধ করতে হবে ।
ব্যাকটিক্স বা পপেন ব্যবহার করা প্রায়শই আপনি যা করতে চান তা আসলে, এটি আসলে জিজ্ঞাসিত প্রশ্নের উত্তর দেয় না। system
আউটপুট ক্যাপচারের জন্য বৈধ কারণ থাকতে পারে (সম্ভবত স্বয়ংক্রিয় পরীক্ষার জন্য)। একটু গুগলিং একটি উত্তর সরিয়ে নিয়েছিল আমি ভেবেছিলাম অন্যের সুবিধার্থে আমি এখানে পোস্ট করব।
যেহেতু আমার উদাহরণটি পরীক্ষা করার জন্য এটির প্রয়োজন ছিল, প্রকৃত 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 / লগ) এ পুনঃনির্দেশ করুন:
system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])
দীর্ঘ চলমান কমান্ডের জন্য, এটি আউটপুটটিকে রিয়েল টাইমে সঞ্চয় করবে। আপনি, আইও.পাইপ ব্যবহার করে আউটপুট সংরক্ষণ করতে পারেন এবং এটি কার্নেল # সিস্টেম থেকে পুনর্নির্দেশ করতে পারেন।
প্রত্যক্ষ সিস্টেম (...) প্রতিস্থাপন হিসাবে আপনি Open3.popen3 (...) ব্যবহার করতে পারেন
আরও আলোচনা: http://tech.natemurray.com/2007/03/ruby- Shell- commands.html
এটি এটিকে এখানে যুক্ত করে খুঁজে পেলাম না, পুরো আউটপুট পেতে আমার কিছু সমস্যা হয়েছিল।
আপনি যদি ব্যাকটিক ব্যবহার করে STDERR ক্যাপচার করতে চান তবে আপনি STDERR কে STDOUT এ পুনর্নির্দেশ করতে পারেন।
আউটপুট = `গ্রেপ হোস্ট / প্রাইভেট / ইত্যাদি / * 2> & 1``
উত্স: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html