ruby - مسلسل - استدعاء أوامر قذيفة من روبي




مسلسل روبي روبي الحلقه الرابعه (14)

أسهل طريقة هي ، على سبيل المثال:

reboot = `init 6`
puts reboot

كيف يمكنني استدعاء أوامر shell من داخل برنامج Ruby؟ كيف يمكنني الحصول على إخراج من هذه الأوامر مرة أخرى إلى روبي؟


أنا بالتأكيد لست خبيرا في روبي ، لكنني سأعطيه فرصة:

$ irb 
system "echo Hi"
Hi
=> true

يجب أن تكون قادرًا أيضًا على القيام بأشياء مثل:

cmd = 'ls'
system(cmd)

إذا كنت حقًا بحاجة إلى Bash ، فكل ملاحظة في إجابة "الأفضل".

أولاً ، لاحظ أنه عندما ينادي روبي بالصدفة ، فإنه يستدعي عادة /bin/sh ، وليس Bash. بعض بناء الجملة Bash غير معتمد من قبل /bin/sh على جميع الأنظمة.

إذا كنت بحاجة إلى استخدام Bash ، فأدخل bash -c "your Bash-only command" داخل طريقة الاتصال المرغوبة.

quick_output = system("ls -la")

quick_bash = system("bash -c 'ls -la'")

لاختبار:

system("echo $SHELL") system('bash -c "echo $SHELL"')

أو إذا كنت تقوم بتشغيل ملف نصي موجود (على سبيل المثال ، script_output = system("./my_script.sh") ) فيجب على Ruby احترام shebang ، لكن يمكنك دائمًا استخدام system("bash ./my_script.sh") للتأكد ( رغم أنه قد يكون هناك حمل بسيط من /bin/sh يعمل /bin/bash ، إلا أنك لن تلاحظ على الأرجح.


إعطاء الأوامر على سبيل المثال attrib

require 'open3'

a="attrib"
Open3.popen3(a) do |stdin, stdout, stderr|
  puts stdout.read
end

لقد وجدت أنه على الرغم من أن هذه الطريقة لا تنسى مثل النظام ("thecommand") أو thecommand في backticks ، فإن الشيء الجيد في هذه الطريقة مقارنة بالطرق الأخرى .. على سبيل المثال ، يبدو أن backticks لا تسمح لي بوضع 'الأمر الذي أقوم بتشغيله / تخزينه هو الأمر الذي أريد تشغيله في متغير ، ولا يبدو أن النظام ("thecommand") يتيح لي الحصول على الإخراج. في حين أن هذه الطريقة تتيح لي القيام بكل من هذه الأشياء ، وتتيح لي الوصول إلى stdin و stdout و stderr بشكل مستقل.

https://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html

http://ruby-doc.org/stdlib-2.4.1/libdoc/open3/rdoc/Open3.html


إليك طريقة رائعة استخدمها في برنامج نصي روبي على نظام التشغيل X (حتى أتمكن من بدء تشغيل برنامج نصي والحصول على تحديث حتى بعد التبديل بعيدًا عن النافذة):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )


الطريقة التي أحب القيام بها هي استخدام %x حرفية ، مما يجعل من السهل (والقراءة!) استخدام علامات الاقتباس في أمر ، مثل ذلك:

directorylist = %x[find . -name '*test.rb' | sort]

والتي ، في هذه الحالة ، ستقوم بتعبئة قائمة الملفات مع جميع ملفات الاختبار ضمن الدليل الحالي ، والتي يمكنك معالجتها كما هو متوقع:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end

المفضل هو Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }

بعض الأشياء التي يجب التفكير فيها عند الاختيار بين هذه الآليات هي:

  1. هل تريد فقط stdout أو هل تحتاج stderr كذلك؟ أو حتى فصلها؟
  2. ما حجم انتاجك؟ هل تريد الاحتفاظ بالنتيجة بأكملها في الذاكرة؟
  3. هل ترغب في قراءة بعض من الإخراج الخاص بك بينما لا تزال تعمل العملية الفرعية؟
  4. هل تحتاج إلى رموز النتائج؟
  5. هل تحتاج إلى عنصر روبي يمثل العملية ويسمح لك بقتله عند الطلب؟

قد تحتاج إلى أي شيء بدءًا من backticks البسيطة (``) و system () و IO.popen إلى Kernel.fork / Kernel.exec مع IO.pipe و IO.select .

قد ترغب أيضًا في إلقاء المهلات في المزيج إذا استغرقت العملية الفرعية وقتًا طويلاً في التنفيذ.

لسوء الحظ ، هذا يعتمد كثيرا.


خيار واحد آخر:

عندما انت:

  • تحتاج stderr وكذلك stdout
  • لا يمكن / لن يستخدم Open3 / Open4 (يرمي استثناءات في NetBeans على جهاز Mac الخاص بي ، ولا أعرف لماذا)

يمكنك استخدام إعادة توجيه shell:

puts %x[cat bogus.txt].inspect
  => ""

puts %x[cat bogus.txt 2>&1].inspect
  => "cat: bogus.txt: No such file or directory\n"

بناء الجملة 2>&1 يعمل عبر Linux و Mac و Windows منذ الأيام الأولى من MS-DOS.


ليست في الحقيقة إجابة ولكن ربما شخص ما سيجد هذا مفيدًا ، وفيما يتعلق بهذا.

عند استخدام TK GUI على Windows ، وتحتاج إلى استدعاء أوامر shell من rubyw ، فستظل لديك دائمًا نافذة cmd مزعجة تظهر لأقل من ثانية.

لتجنب هذا يمكنك استخدام

WIN32OLE.new('Shell.Application').ShellExecute('ipconfig > log.txt','','','open',0)

أو

WIN32OLE.new('WScript.Shell').Run('ipconfig > log.txt',0,0)

سيقوم كلاهما بتخزين إخراج ipconfig داخل "log.txt" ، ولكن لن يتم إنشاء نوافذ.

ستحتاج U إلى require 'win32ole' داخل البرنامج النصي الخاص بك.

system() و exec() و spawn() جميعها ستظهر لك هذه النافذة المزعجة عند استخدام TK و rubyw.


يستند هذا التفسير إلى نص روبي علق من صديق لي. إذا كنت ترغب في تحسين البرنامج النصي ، فلا تتردد في تحديثه على الرابط.

أولاً ، لاحظ أنه عندما ينادي روبي بالصدفة ، فإنه يستدعي عادة /bin/sh ، وليس Bash. بعض بناء الجملة Bash غير معتمد من قبل /bin/sh على جميع الأنظمة.

فيما يلي طرق لتنفيذ البرنامج النصي shell:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` ، وتسمى عادة backticks - `cmd`

    هذا يشبه العديد من اللغات الأخرى ، بما في ذلك Bash و PHP و Perl.

    إرجاع النتيجة (أي الإخراج القياسي) لأمر shell.

    المستندات: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
  2. بناء الجملة المضمنة ، %x( cmd )

    تتبع حرف x هو محدد ، والذي يمكن أن يكون أي حرف. إذا كان المحدد هو أحد الأحرف ( أو [ ، { ، أو < ، يتكون الحرفي من الأحرف حتى محدد الإغلاق المطابق ، مع الأخذ في الاعتبار أزواج المحدد المتداخل. بالنسبة لجميع المحددات الأخرى ، فإن الحرفي يضم الأحرف حتى الحدوث التالي لحرف المحدد. يُسمح باستكمال السلسلة ( #{ ... } ).

    إرجاع النتيجة (أي الإخراج القياسي) لأمر shell ، تمامًا مثل backticks.

    المستندات: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

    value = %x( echo 'hi' )
    value = %x[ #{cmd} ]
  3. Kernel#system

    ينفذ الأمر المحدد في مجلد فرعي.

    إرجاع true إذا تم العثور على الأمر وتشغيله بنجاح ، false .

    المستندات: http://ruby-doc.org/core/Kernel.html#method-i-system

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
  4. Kernel#exec

    يستبدل العملية الحالية عن طريق تشغيل الأمر الخارجي المحدد.

    لا يعود ، يتم استبدال العملية الحالية ولا تستمر أبدًا.

    المستندات: http://ruby-doc.org/core/Kernel.html#method-i-exec

    exec( "echo 'hi'" )
    exec( cmd ) # Note: this will never be reached because of the line above

إليك بعض النصائح الإضافية: $? ، وهو نفس $CHILD_STATUS ، يصل إلى حالة آخر أمر تم تنفيذه في النظام إذا كنت تستخدم backticks أو system() أو %x{} . يمكنك بعد ذلك الوصول إلى خصائص exitstatus :

$?.exitstatus

لمزيد من القراءة ، انظر:


يمكننا تحقيق ذلك بطرق متعددة.

باستخدام Kernel#exec ، لا شيء بعد تنفيذ هذا الأمر:

exec('ls ~')

باستخدام backticks or %x

`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"

باستخدام أمر Kernel#system ، تُرجع true إذا نجحت ، false إذا لم تنجح ، وتُرجع nil إذا فشل تنفيذ الأمر:

system('ls ~')
=> true

  • طريقة backticks هي أسهل طريقة لاستدعاء أوامر shell من روبي. تقوم بإرجاع نتيجة الأمر shell.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`




interop