ruby रूबी से कॉलिंग शेल कमांड




shell interop (16)

उपर्युक्त उत्तर पहले से ही बहुत अच्छे हैं, लेकिन मैं वास्तव में निम्नलिखित सारांश लेख साझा करना चाहता हूं: " http://tech.natemurray.com/2007/03/ruby-shell-commands.html "

असल में, यह हमें बताता है:

Kernel#exec :

exec 'echo "hello $HOSTNAME"'

system और $? :

system 'false' 
puts $?

बैकिक्स (`):

today = `date`

IO#popen :

IO.popen("date") { |f| puts f.gets }

Open3#popen3 - stdlib:

require "open3"
stdin, stdout, stderr = Open3.popen3('dc') 

Open4#popen4 - एक मणि:

require "open4" 
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]

मैं रूबी प्रोग्राम के अंदर से शैल कमांड कैसे कॉल करूं? फिर मैं इन आदेशों से रूबी में आउटपुट कैसे प्राप्त करूं?


  • बैकटीक्स विधि विधि रूबी से खोल कमांड को कॉल करने का सबसे आसान तरीका है। यह खोल कमांड का परिणाम देता है।

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

यहां एक अच्छा है जिसे मैं ओएस एक्स पर एक रूबी स्क्रिप्ट में उपयोग करता हूं (ताकि मैं एक स्क्रिप्ट शुरू कर सकूं और विंडो से दूर टॉगल करने के बाद भी अपडेट प्राप्त कर सकूं):

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

यदि आपके पास सामान्य मामले की तुलना में अधिक जटिल मामला है (जिसे `` साथ संभाला नहीं जा सकता है) तो here Kernel.spawn() । बाहरी आदेशों को निष्पादित करने के लिए स्टॉक रूबी द्वारा प्रदान किया गया यह सबसे सामान्य / पूर्ण-विशेषीकृत प्रतीत होता है।

उदाहरण के लिए आप इसका उपयोग कर सकते हैं:

  • प्रक्रिया समूह बनाएं (विंडोज़)
  • फ़ाइलों को / प्रत्येक-दूसरे में रीडायरेक्ट, आउट, त्रुटि।
  • एनवी वर्र्स सेट करें, उमास्क
  • कमांड निष्पादित करने से पहले डीआईआर बदलें
  • सीपीयू / डेटा / के लिए संसाधन सीमा सेट करें ...
  • अन्य उत्तरों में अन्य विकल्पों के साथ किया जा सकता है, लेकिन अधिक कोड के साथ।

आधिकारिक here में पर्याप्त उदाहरण हैं।

env: hash
  name => val : set the environment variable
  name => nil : unset the environment variable
command...:
  commandline                 : command line string which is passed to the standard shell
  cmdname, arg1, ...          : command name and one or more arguments (no shell)
  [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
  clearing environment variables:
    :unsetenv_others => true   : clear environment variables except specified by env
    :unsetenv_others => false  : dont clear (default)
  process group:
    :pgroup => true or 0 : make a new process group
    :pgroup => pgid      : join to specified process group
    :pgroup => nil       : dont change the process group (default)
  create new process group: Windows only
    :new_pgroup => true  : the new process is the root process of a new process group
    :new_pgroup => false : dont create a new process group (default)
  resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
    :rlimit_resourcename => limit
    :rlimit_resourcename => [cur_limit, max_limit]
  current directory:
    :chdir => str
  umask:
    :umask => int
  redirection:
    key:
      FD              : single file descriptor in child process
      [FD, FD, ...]   : multiple file descriptor in child process
    value:
      FD                        : redirect to the file descriptor in parent process
      string                    : redirect to file with open(string, "r" or "w")
      [string]                  : redirect to file with open(string, File::RDONLY)
      [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
      [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
      [:child, FD]              : redirect to the redirected file descriptor
      :close                    : close the file descriptor in child process
    FD is one of follows
      :in     : the file descriptor 0 which is the standard input
      :out    : the file descriptor 1 which is the standard output
      :err    : the file descriptor 2 which is the standard error
      integer : the file descriptor of specified the integer
      io      : the file descriptor specified as io.fileno
  file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
    :close_others => false : inherit fds (default for system and exec)
    :close_others => true  : dont inherit (default for spawn and IO.popen)

आप पर्ल के समान बैकटिक ऑपरेटरों (`) का भी उपयोग कर सकते हैं:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

अगर आपको कुछ आसान चाहिए तो हंडी।

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


यदि आपको "सर्वश्रेष्ठ" उत्तर में नोट के अनुसार वास्तव में बैश की आवश्यकता है।

सबसे पहले, ध्यान दें कि जब रूबी एक खोल में कॉल करता है, तो यह आमतौर पर बैश नहीं होता /bin/sh । कुछ बैश वाक्यविन्यास सभी प्रणालियों पर /bin/sh द्वारा समर्थित नहीं है।

यदि आपको बैश का उपयोग करने की आवश्यकता है, तो अपनी वांछित कॉलिंग विधि के अंदर 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") ) रूबी को script_output = system("./my_script.sh") सम्मान करना चाहिए , लेकिन आप हमेशा यह सुनिश्चित करने के लिए system("bash ./my_script.sh") का उपयोग कर सकते हैं ( यद्यपि /bin/sh running /bin/bash से थोड़ी सी ओवरहेड हो सकती है, तो शायद आपको नोटिस नहीं होगा।


एक और विकल्प:

जब आप:

  • stderr के साथ ही stdout की जरूरत है
  • ओपन 3 / ओपन 4 का उपयोग नहीं कर सकता / नहीं (वे मेरे मैक पर नेटबीन में अपवाद फेंकते हैं, कोई विचार नहीं)

आप खोल पुनर्निर्देशन का उपयोग कर सकते हैं:

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 , मैक और Windows काम करता है।


इस उत्तर के आधार पर एक फ्लोचार्ट है। एक टर्मिनल अनुकरण करने के लिए script का उपयोग करके भी देखें।


यह स्पष्टीकरण मेरे एक दोस्त से रूबी लिपि पर टिप्पणी की गई है। यदि आप स्क्रिप्ट को बेहतर बनाना चाहते हैं, तो इसे लिंक पर अपडेट करने के लिए स्वतंत्र महसूस करें।

सबसे पहले, ध्यान दें कि जब रूबी एक खोल में कॉल करता है, तो यह आमतौर पर बैश नहीं होता /bin/sh । कुछ बैश वाक्यविन्यास सभी प्रणालियों पर /bin/sh द्वारा समर्थित नहीं है।

शेल स्क्रिप्ट निष्पादित करने के तरीके यहां दिए गए हैं:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , जिसे आमतौर पर बैकटीक्स कहा जाता है - `cmd`

    यह बैश, PHP, और पर्ल समेत कई अन्य भाषाओं की तरह है।

    खोल कमांड का परिणाम देता है।

    डॉक्स: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. अंतर्निहित वाक्यविन्यास, %x( cmd )

    x चरित्र के बाद एक delimiter है, जो किसी भी चरित्र हो सकता है। यदि डिलीमीटर वर्णों में से एक है ( , [ , { , या < , शाब्दिक मिलान वाले समापन डिलीमीटर तक वर्णों में से एक है, नेस्टेड डेलीमीटर जोड़े का विवरण लेना। अन्य सभी डिलीमीटरों के लिए, शाब्दिक अक्षर को वर्णित करता है डेलीमीटर चरित्र की अगली घटना। स्ट्रिंग इंटरपोलेशन #{ ... } की अनुमति है।

    बैकटिक्स की तरह, शेल कमांड का परिणाम देता है।

    डॉक्स: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

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

    एक सबहेल में दिया गया आदेश निष्पादित करता है।

    अगर आदेश पाया गया और सफलतापूर्वक भाग गया, तो false , अन्यथा 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 जैसा ही है, यदि आप बैकटिक्स, system() या %x{} उपयोग करते हैं तो अंतिम सिस्टम निष्पादित कमांड की स्थिति तक पहुंच प्राप्त करता है। फिर आप exitstatus और pid गुणों तक पहुंच सकते हैं:

$?.exitstatus

अधिक पढ़ने के लिए देखें:


इन तंत्रों के बीच चयन करते समय कुछ चीजें सोचने के लिए हैं:

  1. क्या आप सिर्फ स्टडआउट चाहते हैं या आपको स्टेडर की भी आवश्यकता है? या यहां तक ​​कि अलग हो गए?
  2. आपका आउटपुट कितना बड़ा है? क्या आप पूरे परिणाम को स्मृति में रखना चाहते हैं?
  3. क्या आप अपने कुछ आउटपुट को पढ़ना चाहते हैं जबकि सबप्रोसेस अभी भी चल रहा है?
  4. क्या आपको परिणाम कोड चाहिए?
  5. क्या आपको एक रूबी ऑब्जेक्ट की आवश्यकता है जो प्रक्रिया का प्रतिनिधित्व करता है और आपको मांग पर मारने देता है?

आपको सरल बैकटिक्स (``), सिस्टम (), और IO.popen से IO.popen और IO.popen के साथ पूर्ण Kernel.fork / Kernel.exec से IO.pipe IO.select

यदि उप-प्रोसेस को निष्पादित करने में बहुत लंबा समय लगता है तो आप समय में मिश्रण को फेंकना भी चाह सकते हैं।

दुर्भाग्य से, यह बहुत निर्भर करता है


मैं निश्चित रूप से रूबी विशेषज्ञ नहीं हूं, लेकिन मैं इसे एक शॉट दूंगा:

$ irb 
system "echo Hi"
Hi
=> true

आपको चीजों को भी करने में सक्षम होना चाहिए:

cmd = 'ls'
system(cmd)

यहां दिए गए उत्तरों का उपयोग और मिहाई के जवाब में जुड़ा हुआ, मैंने एक समारोह को एक साथ रखा जो इन आवश्यकताओं को पूरा करता है:

  1. अच्छी तरह से STDOUT और STDERR को कैप्चर करता है ताकि जब मेरी स्क्रिप्ट कंसोल से चलती है तो वे "रिसाव नहीं" करते हैं।
  2. तर्क को सरणी में सरणी में पारित करने की अनुमति देता है, इसलिए भागने के बारे में चिंता करने की आवश्यकता नहीं है।
  3. आदेश की निकास स्थिति को कैप्चर करता है ताकि त्रुटि होने पर यह स्पष्ट हो।

बोनस के रूप में, यह उन मामलों में STDOUT भी लौटाएगा जहां शेल कमांड सफलतापूर्वक बाहर निकलता है (0) और STDOUT पर कुछ भी डालता है। इस तरह, यह system से अलग system , जो इस तरह के मामलों में true है।

कोड निम्नानुसार है। विशिष्ट कार्य system_quietly :

require 'open3'

class ShellError < StandardError; end

#actual function:
def system_quietly(*cmd)
  exit_status=nil
  err=nil
  out=nil
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
    err = stderr.gets(nil)
    out = stdout.gets(nil)
    [stdin, stdout, stderr].each{|stream| stream.send('close')}
    exit_status = wait_thread.value
  end
  if exit_status.to_i > 0
    err = err.chomp if err
    raise ShellError, err
  elsif out
    return out.chomp
  else
    return true
  end
end

#calling it:
begin
  puts system_quietly('which', 'ruby')
rescue ShellError
  abort "Looks like you don't have the `ruby` command. Odd."
end

#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"

जिस तरह से मैं ऐसा करना चाहता हूं वह %x अक्षर का उपयोग कर रहा है, जो कमांड में उद्धरणों का उपयोग करने के लिए इसे आसान (और पठनीय!) बनाता है, जैसे:

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

जो, इस मामले में, मौजूदा निर्देशिका के तहत सभी परीक्षण फ़ाइलों के साथ फ़ाइल सूची पॉप्युलेट करेगा, जिसे आप अपेक्षित रूप से संसाधित कर सकते हैं:

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

सबसे आसान तरीका है, उदाहरण के लिए:

reboot = `init 6`
puts reboot

हम इसे कई तरीकों से प्राप्त कर सकते हैं।

Kernel#exec का प्रयोग करके, इस कमांड को निष्पादित करने के बाद कुछ नहीं:

exec('ls ~')

backticks or %x का उपयोग करना

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

Kernel#system कमांड का उपयोग करना, सफल होने पर true लौटाता true , असफल होने पर false और कमांड निष्पादन विफल होने पर nil लौटाता है:

system('ls ~')
=> true

एक आदेश दिया गया है जैसे attrib

require 'open3'

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

मैंने पाया है कि यह विधि यादगार नहीं है जैसे कि सिस्टम ("कमांड") या बैकटिक्स में कमांड, अन्य तरीकों की तुलना में इस विधि के बारे में एक अच्छी बात है .. उदाहरण के लिए बैकटीक्स मुझे 'रखता है 'कमांड जिसे मैं एक चर में चलाने के लिए कमांड को चलाता / संग्रह करता हूं, और सिस्टम ("कमांड") मुझे आउटपुट प्राप्त करने की प्रतीत नहीं करता है। जबकि यह विधि मुझे उन दोनों चीजों को करने देती है, और यह मुझे स्वतंत्र रूप से 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





interop