রুবিতে সিস্টেমের () কলগুলির আউটপুট পাওয়া


309

আমি যদি রুবিতে কার্নেল # সিস্টেম ব্যবহার করে একটি কমান্ড কল করি, তবে আমি কীভাবে এর আউটপুট পেতে পারি?

system("ls")


এটি একটি খুব হাতের থ্রেড, ধন্যবাদ। কমান্ড চালাবার এবং প্রতিক্রিয়া পাওয়ার শ্রেণি নমুনা কোডে দুর্দান্ত।
15 ই এলোমিনেট করুন

3
ভবিষ্যতের গুগলদের জন্য। আপনি যদি অন্যান্য সিস্টেম কমান্ড কল এবং তাদের পার্থক্য সম্পর্কে জানতে চান তবে এই এসও উত্তরটি দেখুন
উজবেজোন

উত্তর:


347

আমি বিশৃঙ্খলার উত্তর প্রসারিত এবং স্পষ্ট করতে চাই কিছুটা ।

আপনি যদি আপনার কমান্ডটি ব্যাকটিক্স দিয়ে ঘিরে থাকেন তবে আপনার (স্পষ্টভাবে) কল সিস্টেম () মোটেও দরকার নেই। ব্যাকটিকস কমান্ডটি কার্যকর করে এবং আউটপুটটিকে স্ট্রিং হিসাবে ফিরিয়ে দেয়। তারপরে আপনি ভেরিয়েবলের মতো মান নির্ধারণ করতে পারেন:

output = `ls`
p output

অথবা

printf output # escapes newline chars

4
আমার কমান্ডের অংশ হিসাবে যদি আমার একটি ভেরিয়েবল দেওয়ার দরকার হয় তবে কী হবে? এটি, যখন ব্যাকটিকগুলি ব্যবহার করা হয় তখন সিস্টেম ("ls" + ফাইলের নাম) এর মতো কোনও কী অনুবাদ করতে পারে?
বিজয় দেব

47
আপনি যত আপনি নিয়মিত স্ট্রিং সঙ্গে would শুধু অভিব্যক্তি মূল্যায়ন করতে পারেন: ls #{filename}
ক্রেগ ওয়াকার

36
এই উত্তরটি পরামর্শ দেওয়া যায় না: এটি অ সঞ্জনিত ব্যবহারকারী ইনপুটটির নতুন সমস্যাটি প্রবর্তন করে।
ডগওয়েদার

4
@ ডগওয়েদার: এটি সত্য হতে পারে তবে এটি কি অন্য পদ্ধতির চেয়ে আলাদা?
ক্রেগ ওয়াকার 15

20
আপনি যদি স্ট্যাডারকে ক্যাপচার করতে চান তবে আপনার কমান্ডের শেষে 2> & 1 চাপুন। যেমন আউটপুট =command 2>&1

243

সচেতন হোন যে আপনি যেখানে স্ট্রিং ব্যবহার করেছেন সেখানে ব্যবহারকারীরা মানগুলি সরবরাহ করে এমন সমাধানগুলি 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

মনে রাখবেন যে ব্লক ফর্মটি স্টিডিন, স্টডআউট এবং স্ট্ডারকে স্বয়ংক্রিয়ভাবে বন্ধ করবে - অন্যথায় তারা স্পষ্টভাবে বন্ধ করতে হবে ।

এখানে আরও তথ্য: রুবীতে স্যানিটারি শেল কমান্ড বা সিস্টেম কল গঠন


26
এটিই হ'ল একমাত্র উত্তর যা প্রকৃতপক্ষে প্রশ্নের উত্তর দেয় এবং নতুনগুলি (নিরবচ্ছিন্ন ইনপুট) প্রবর্তন না করেই সমস্যার সমাধান করে।
ডগওয়েদার

2
ধন্যবাদ! এই আমি উত্তর প্রত্যাশা ছিল সাজানোর। একটি সংশোধন: getsকলগুলি আর্গুমেন্টটি পাস করবে nil, অন্যথায় আমরা আউটপুটটির প্রথম লাইনটি পাই। সুতরাং যেমন stdout.gets(nil)
গ্রেগ দাম

3
stdin, stdout এবং stderr অবরুদ্ধ- বিন্যাসে স্পষ্টভাবে বন্ধ করা উচিত ।
ইয়ারিন

কেউ কি জানেন যে রুবি ২.০ বা ২.১ এ কিছু পরিবর্তন হয়েছে? সম্পাদনা বা মন্তব্যগুলি প্রশংসা করা হবে ;-)
সাইমন হারলিমন

1
আমি মনে করি যে চারপাশের আলোচনার Open3.popen3একটি বড় সমস্যা অনুপস্থিত: আপনার যদি এমন একটি সাবপ্রসেস থাকে যা পাইপ ধরে রাখার চেয়ে স্টডআউটকে আরও ডেটা লেখেন, সাবপ্রসেসটি স্থগিত হয়ে যায় stderr.writeএবং আপনার প্রোগ্রামটি আটকে যায় stdout.gets(nil)
হাজেলো

165

কেবল রেকর্ডের জন্য, আপনি উভয়ই চাইলে (আউটপুট এবং অপারেশন ফলাফল) আপনি করতে পারেন:

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

4
আমি ঠিক এটিই খুঁজছিলাম। ধন্যবাদ.
jdl

12
এটি কেবল স্টডআউটকে ক্যাপচার করে, এবং স্ট্ডার কনসোলে যায়। output=`ls no_existing_file 2>&1`; result=$?.success?
স্ট্যাডার

8
এই উত্তরটি অনিরাপদ এবং ব্যবহার করা উচিত নয় - যদি কমান্ডটি একটি ধ্রুবক ব্যতীত অন্য কিছু হয় তবে ব্যাকটিক সিনট্যাক্সটি সম্ভবত একটি বাগের কারণ হতে পারে, সম্ভবত নিরাপত্তার দুর্বলতা দেখা দেয়। (এবং এটি ধ্রুবক হলেও, সম্ভবত এটি পরে কোনওটিকে অ-ধ্রুবকের জন্য ব্যবহার করতে এবং বাগের কারণ ঘটায়)) সঠিক সমাধানের জন্য সাইমন হারলিম্যানের উত্তর দেখুন ।
গ্রেগ দাম

23
ব্যবহারকারীর ইনপুট থেকে বাঁচার প্রয়োজনীয়তা সম্পর্কে বোঝার জন্য গ্রেড প্রাইস থেকে কুডোস, তবে লিখিত হিসাবে এটি অনিরাপদ বলে এই উত্তরটি বলা ঠিক হবে না। উল্লিখিত ওপেন 3 পদ্ধতিটি আরও জটিল এবং আরও নির্ভরশীলতার পরিচয় দেয় এবং যুক্তি যে কেউ "পরে এটি অ-ধ্রুবক হিসাবে ব্যবহার করবে" এটি স্ট্রোম্যান। সত্য, আপনি সম্ভবত এগুলিকে একটি রেল অ্যাপ্লিকেশনটিতে ব্যবহার করবেন না, তবে অবিশ্বস্ত ব্যবহারকারী ইনপুট হওয়ার কোনও সম্ভাবনা ছাড়াই একটি সাধারণ সিস্টেম ইউটিলিটি স্ক্রিপ্টের জন্য ব্যাকটিকগুলি পুরোপুরি ঠিক আছে এবং এগুলি ব্যবহারের ক্ষেত্রে কারও খারাপ লাগা উচিত নয়।
sbeam

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

সমস্যাটি হ'ল এটি আউটপুটটির পরিবর্তে প্রস্থান কোডটি ফেরত দেয় এবং পরবর্তীটিকে ক্যাপচার করা গোলাকার এবং অগোছালো।

এই থ্রেডের সেরা উত্তরটি এখন পর্যন্ত ওপেন 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')

2
এটা সঠিক উত্তর. এটি সবচেয়ে তথ্যবহুলও। অনুপস্থিত শুধুমাত্র জিনিস হ'ল স্ট্যান্ড * গুলি বন্ধ করার বিষয়ে একটি সতর্কতা। দেখুন এই অন্য মন্তব্য : require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read } নোট ব্লক গঠন করবে স্বয়ংক্রিয় ঘনিষ্ঠ stdin, stdout- এ এবং stderr- অন্যথায় তারা হতে চাই যে স্পষ্টভাবে বন্ধ
পিটার এইচ বোলিং

@ PeterH.Boling: শ্রেষ্ঠ আমি সচেতন আছি, capture2, capture2eএবং capture3এছাড়াও ঘনিষ্ঠ তাদের std * স্বয়ংক্রিয়ভাবে s। (খুব কমপক্ষে, আমি কখনই আমার শেষ পর্যন্ত সমস্যার দিকে
যাইনি

ব্লক ফর্মটি ব্যবহার না করে কোনও কোনও কোডবেস কখন বন্ধ করা উচিত তা জানার উপায় নেই, সুতরাং আমি অত্যন্ত সন্দেহ করি যে সেগুলি বন্ধ রয়েছে। আপনি সম্ভবত কোনও সমস্যায় পড়েননি কারণ এগুলি বন্ধ না করে অল্পকালীন প্রক্রিয়াতে সমস্যা দেখা দেবে না এবং আপনি যদি দীর্ঘকালীন প্রক্রিয়াটি প্রায়শই পুনরায় চালু করেন তবে অডিও আপনি সেখানে প্রদর্শিত হবে না যদি আপনি স্ট্যান্ড * এস না খোলেন তবে একটি লুপ লিনাক্সের একটি উচ্চ ফাইল বর্ণনাকারী সীমা রয়েছে, যা আপনি আঘাত করতে পারেন তবে এটি আঘাত না করা পর্যন্ত আপনি "বাগ" দেখতে পাবেন না।
পিটার এইচ। বলিং

2
@ পিটারএইচ.বোলিং: না না, উত্স কোডটি দেখুন। ফাংশনগুলি কেবল চারপাশে মোড়ানোOpen3#popen2 , popen2eএবং popen3একটি পূর্বনির্ধারিত ব্লক সহ: রুবি- ডক.আর.এস.সি.ডি.লি.বি.২.১.১
ডেনিস ডি বার্নার্ডি

1
@ ডেনিস ডি বার্নার্ডি সম্ভবত আপনি মিস করেছেন যে আমি একই শ্রেণীর নথিগুলির সাথে লিঙ্ক করেছি (যদিও রুবি ২.০.০ এর জন্য এবং একটি ভিন্ন পদ্ধতি। রুবি- ডক.আর.অর্গ.এসটিডিবিব ২.১.১ / লিবিডোক / ওপেন //rdoc/… উদাহরণ থেকে : `` `স্টিডিন, স্টডআউট, স্টার্ডার, ওয়েট_থ্র = ওপেন ৩.পিপেন ৩ ([এনভিভি,] সেমিডি ... [, অপ্টস]) পিড = ওয়েট_থার [: পিআইডি] # শুরু পিডির প্রক্রিয়া ... স্টিডিন.ক্লোজ # স্টিডিন , stdout এবং stderr এই ফর্মটিতে স্পষ্টভাবে বন্ধ করা উচিত। stdout.close stderr.close just `` আমি কেবল ডকুমেন্টেশনের উদ্ধৃতি দিচ্ছিলাম। "# স্টিডিন, স্টাডআউট এবং স্টার্ডার এই ফর্মটিতে স্পষ্টভাবে বন্ধ করা উচিত।"
পিটার এইচ বোলিং

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

ব্লগ পোস্ট জে ক্ষেত্রসমূহ দ্বারা [..] সিস্টেম ব্যবহার মধ্যে পার্থক্য বিস্তারিতভাবে ব্যাখ্যা করে, Exec এবং% এক্স।


2
% X [] ব্যবহারের পরামর্শের জন্য ধন্যবাদ। এটি কেবলমাত্র আমার একটি সমস্যার সমাধান করেছিল যেখানে আমি ম্যাক ওএস এক্স-এ রুবি স্ক্রিপ্টে টিক্স ব্যবহার করেছি Cy সাইগউইনের সাথে উইন্ডোজ মেশিনে একই স্ক্রিপ্টটি চালানোর সময়, এটি পিছনের টিকগুলির কারণে ব্যর্থ হয়েছিল, তবে% x [] এর সাথে কাজ করেছিল।
হেনরিক ওয়ার্ন

22

আপনার যদি যুক্তিগুলি থেকে বাঁচার দরকার হয় তবে রুবি ১.৯-এ আইও.পপেন একটি অ্যারে গ্রহণ করে:

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

আপনি ব্যাকটিক্স ব্যবহার:

`ls`

5
ব্যাকটিকগুলি টার্মিনালে আউটপুট উত্পাদন করে না।
মই

3
এটি স্টডারার উত্পাদন করে না তবে এটি স্টডআউট দেয়।
নিকোলায় কনড্রেটেনকো

1
এটি stdout বা stderr লিখেন না। আসুন এই উদাহরণটি ব্যবহার করে দেখুন ruby -e '%x{ls}'- দ্রষ্টব্য, কোনও আউটপুট নেই। (FYI %x{}ব্যাকটিক সমতূল্য।)
ocodo

এটি দুর্দান্ত কাজ করেছে। ব্যবহারের shফলে আউটপুটটি কনসোল (যেমন STDOUT) তে প্রতিস্থাপিত হবে এবং ফিরে আসবে। এটা হয় না।
জোশুয়া পিন্টার

19

আর একটি উপায় হ'ল:

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

মনে রাখবেন যে "এলএস" খোলার আগে "পাইপ" চরিত্রটি। এটি প্রোগ্রামগুলির স্ট্যান্ডার্ড ইনপুটগুলির পাশাপাশি এর স্ট্যান্ডার্ড আউটপুট পড়ার জন্য ডেটা ফিড করতেও ব্যবহার করা যেতে পারে।



14

আমি খুঁজেছি যে আপনার যদি ফেরতের মান প্রয়োজন হয় তবে নিম্নলিখিতগুলি কার্যকর হয়:

result = %x[ls]
puts result

আমি বিশেষভাবে আমার মেশিনে সমস্ত জাভা প্রক্রিয়াগুলির পিডগুলি তালিকাবদ্ধ করতে চেয়েছি এবং এটি ব্যবহার করেছি:

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

এটি একটি দুর্দান্ত সমাধান।
রোনান লরন

13

হিসাবে সাইমন Hürlimann ইতিমধ্যে ব্যাখ্যা , Open3 ব্যাকটিক ইত্যাদি চেয়ে নিরাপদ

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

মনে রাখবেন যে ব্লক ফর্মটি স্টিডিন, স্টডআউট এবং স্ট্ডারকে স্বয়ংক্রিয়ভাবে বন্ধ করবে - অন্যথায় তারা স্পষ্টভাবে বন্ধ করতে হবে ।


9

ব্যাকটিক্স বা পপেন ব্যবহার করা প্রায়শই আপনি যা করতে চান তা আসলে, এটি আসলে জিজ্ঞাসিত প্রশ্নের উত্তর দেয় না। 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


8

আপনি যদি কোনও ফাইল ব্যবহার করে আউটপুটটি পুনঃনির্দেশ করতে চান তবে Kernel#systemআপনি এই জাতীয় বর্ণনাকারীদের সংশোধন করতে পারেন:

স্ট্যান্ডআউট এবং স্টেডারকে অ্যাপেন্ড মোডে একটি ফাইল (/ tmp / লগ) এ পুনঃনির্দেশ করুন:

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

দীর্ঘ চলমান কমান্ডের জন্য, এটি আউটপুটটিকে রিয়েল টাইমে সঞ্চয় করবে। আপনি, আইও.পাইপ ব্যবহার করে আউটপুট সংরক্ষণ করতে পারেন এবং এটি কার্নেল # সিস্টেম থেকে পুনর্নির্দেশ করতে পারেন।



0

এটি এটিকে এখানে যুক্ত করে খুঁজে পেলাম না, পুরো আউটপুট পেতে আমার কিছু সমস্যা হয়েছিল।

আপনি যদি ব্যাকটিক ব্যবহার করে STDERR ক্যাপচার করতে চান তবে আপনি STDERR কে STDOUT এ পুনর্নির্দেশ করতে পারেন।

আউটপুট = `গ্রেপ হোস্ট / প্রাইভেট / ইত্যাদি / * 2> & 1``

উত্স: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.