Вызов команд оболочки из Ruby - PullRequest
976 голосов
/ 05 августа 2008

Как мне вызывать команды оболочки внутри Ruby-программы? Как я могу получить выходные данные этих команд обратно в Ruby?

Ответы [ 20 ]

7 голосов
/ 05 августа 2008

Вы также можете использовать операторы обратного удара (`), аналогично Perl:

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

Удобно, если вам нужно что-то простое.

Какой метод вы хотите использовать, зависит от того, что именно вы пытаетесь достичь; проверьте документы для более подробной информации о различных методах.

6 голосов
/ 30 марта 2017

Самый простой способ, например:

reboot = `init 6`
puts reboot
5 голосов
/ 19 февраля 2012

Мы можем достичь этого несколькими способами.

Используя Kernel#exec, после выполнения этой команды ничего не происходит:

exec('ls ~')

Использование backticks or %x

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

Используя команду Kernel#system, возвращает true в случае успеха, false в случае неудачи и возвращает nil в случае неудачного выполнения команды:

system('ls ~')
=> true
5 голосов
/ 04 ноября 2015

Не забудьте команду spawn, чтобы создать фоновый процесс для выполнения указанной команды. Вы даже можете дождаться его завершения, используя класс Process и возвращенное pid:

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

Док говорит: Этот метод похож на #system, но он не ожидает завершения команды.

5 голосов
/ 21 февраля 2012

Используя ответы здесь и связанные в ответе Михая, я собрал функцию, которая отвечает этим требованиям:

  1. Аккуратно фиксирует STDOUT и STDERR, чтобы они не "просачивались" при запуске моего скрипта из консоли.
  2. Позволяет передавать аргументы в оболочку в виде массива, поэтому вам не нужно беспокоиться об экранировании.
  3. Записывает состояние завершения команды, чтобы было ясно, когда произошла ошибка.

В качестве бонуса этот также будет возвращать STDOUT в случаях, когда команда оболочки успешно завершает работу (0) и помещает что-либо в STDOUT. Таким образом, он отличается от 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"
3 голосов
/ 16 февраля 2017
  • метод backticks `- самый простой способ вызова команд оболочки из ruby. Возвращает результат команды оболочки.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    
3 голосов
/ 11 декабря 2015

Если у вас более сложный случай, чем общий случай (который не может быть обработан с помощью ``), проверьте Kernel.spawn() здесь . Похоже, это наиболее общий / полнофункциональный пакет Ruby для выполнения внешних команд.

например. Вы можете использовать его для:

  • создание групп процессов (Windows)
  • перенаправление, вывод, ошибка в файлы / друг друга.
  • set env vars, umask
  • изменить каталог перед выполнением команды
  • установить ограничения ресурсов для CPU / data /...
  • Делайте все, что можно сделать с другими вариантами в других ответах, но с большим количеством кода.

Официальная ruby ​​документация имеет достаточно хороших примеров.

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)
2 голосов
/ 19 декабря 2017

С учетом команды, например, attrib

require 'open3'

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

Я обнаружил, что хотя этот метод не такой запоминающийся, как, например, system ("thecommand") или thecommand в обратных тегах, хорошая вещь об этом методе по сравнению с другими методами ... например, backticks, похоже, не позволяет мне «помещать» команду, которую я запускаю / сохраняю, команду, которую я хочу запустить в переменной, а system («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

1 голос
/ 05 июля 2018

Не совсем ответ, но, возможно, кто-то найдет это полезным, и это относится к этому.

При использовании TK GUI в Windows, и вам нужно вызывать команды оболочки из 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.

0 голосов
/ 15 октября 2014

Вот классный пример, который я использую в скрипте ruby ​​на OS X (чтобы я мог запустить скрипт и получить обновление даже после переключения из окна):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...