Вызов команд оболочки из Рубина

голоса
862

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

Задан 05/08/2008 в 13:56
источник пользователем
На других языках...                            


20 ответов

голоса
1k

Это объяснение основано на комментировали Руби скрипт из моего друга. Если вы хотите улучшить сценарий, не стесняйтесь , чтобы обновить его по ссылке.

Во- первых, обратите внимание , что , когда Руби взывает к оболочке, это обычно вызывает /bin/sh, не Bash. Некоторые синтаксиса Bash не поддерживается /bin/shна всех системах.

Вот способы, чтобы выполнить скрипт:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , Который обычно называют обратными кавычками - `cmd`

    Это, как и многие другие языки, в том числе Bash, PHP и Perl.

    Возвращает результат команды оболочки.

    Документы: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. Встроенный в синтаксисе, %x( cmd )

    После xсимвола является разделителем, который может быть любым символом. Если разделитель является одним из символов (, [, {или <, в буквальном смысле состоит из символов , до закрытия соответствия разделителя, с учетом вложенных пар разделителей. Для всех других разделителей, буквальные содержат символы до следующего вхождения символа - ограничителя. Строка интерполяции #{ ... }допускается.

    Возвращает результат команды оболочки, так же как и обратные кавычки.

    Документы: 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, обращаются статус последней системы выполняется командой , если вы используете кавычку, system()или %x{}. Вы можете получить доступ к exitstatusи pidсвойства:

$?.exitstatus

Для получения дополнительного чтения смотрите:

Ответил 05/08/2008 d 15:42
источник пользователем

голоса
150

Как я хотел бы сделать это с помощью %xлитерала, что делает его легко использовать кавычки в команде, например , так (и читаемым!):

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

Что, в этом случае, будет заполнять список файлов со всех тестовых файлов в текущем каталоге, который можно обрабатывать, как и ожидалось:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end
Ответил 05/08/2008 d 15:08
источник пользователем

голоса
140

Вот блок - схема алгоритма на основе этого ответа . Смотрите также, используя scriptдля эмуляции терминала .

введите описание изображения здесь

Ответил 19/05/2016 d 17:01
источник пользователем

голоса
58

Вот лучшая статья на моем взгляде , о запуске скриптов в Ruby: « 6 способов для запуска команд оболочки в Рубине ».

Если вам нужно только, чтобы получить выход на использование кавычку.

Мне нужно было более продвинутые вещи, как STDOUT и STDERR, так что я использовал Open4 камень. У вас есть все методы объяснили там.

Ответил 02/09/2008 d 12:05
источник пользователем

голоса
31

Мой любимый open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
Ответил 18/09/2008 d 18:47
источник пользователем

голоса
23

Некоторые вещи, чтобы думать о том, когда выбор между этими механизмами являются:

  1. Вы просто хотите STDOUT или вам нужно STDERR, а? или даже отделяется?
  2. Насколько велик ваш вывод? Вы хотите провести весь результат в памяти?
  3. Вы хотите, чтобы прочитать некоторые из вашего выхода в то время как подпроцесс все еще работает?
  4. Вам необходимы результирующие коды?
  5. Вам нужен объект рубина, который представляет этот процесс и позволяет убить его по требованию?

Возможно , вам что - нибудь из простых обратных кавычек ( ``), система (), и IO.popenв полномасштабный Kernel.fork/ Kernel.execс IO.pipeи IO.select.

Вы также можете бросить тайм-ауты в смесь, если подпроцесс занимает слишком много времени, чтобы выполнить.

К сожалению, это очень зависит .

Ответил 07/08/2008 d 06:10
источник пользователем

голоса
19

Еще один вариант:

Когда ты:

  • нужно STDERR, а также стандартный вывод
  • не может / не будет использовать open3 / Open4 (они бросают исключения в NetBeans на моем Mac, не знаю, почему)

Вы можете использовать перенаправление оболочки:

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.

Ответил 16/06/2010 d 03:13
источник пользователем

голоса
15

Я определенно не эксперт Руби, но я дам ему выстрелили:

$ irb 
system "echo Hi"
Hi
=> true

Вы также должны быть в состоянии делать такие вещи, как:

cmd = 'ls'
system(cmd)
Ответил 05/08/2008 d 14:24
источник пользователем

голоса
11

Ответы выше уже достаточно велик, но я действительно хочу поделиться следующей сводной статьи: « 6 способов выполнения команд оболочки в Рубине »

В основном, это говорит нам:

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>]
Ответил 07/06/2013 d 03:07
источник пользователем

голоса
7

Если вам действительно нужно 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")) рубин должен чтить хижину, но вы всегда можете использовать , system("bash ./my_script.sh")чтобы убедиться , что (хотя может быть небольшими накладными расходами от /bin/shработы /bin/bash, вы , вероятно , не заметите.

Ответил 02/06/2017 d 20:14
источник пользователем

голоса
7

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

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

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

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

Ответил 05/08/2008 d 14:57
источник пользователем

голоса
5

Не забудьте 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но не ждать завершения работы команды.

Ответил 04/11/2015 d 15:04
источник пользователем

голоса
5

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

  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"
Ответил 21/02/2012 d 00:36
источник пользователем

голоса
5

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

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

exec('ls ~')

С помощью backticks or %x

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

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

system('ls ~')
=> true
Ответил 19/02/2012 d 19:07
источник пользователем

голоса
4

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

reboot = `init 6`
puts reboot
Ответил 30/03/2017 d 18:13
источник пользователем

голоса
3
  • Метод `обратных кавычек является самым простым один для вызова команд оболочки из рубина. Она возвращает результат выполнения команды оболочки.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    
Ответил 16/02/2017 d 09:58
источник пользователем

голоса
3

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

Например, вы можете использовать его для:

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

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

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)
Ответил 11/12/2015 d 14:57
источник пользователем

голоса
1

Учитывая команду, например Attrib

require 'open3'

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

Я обнаружил, что в то время как этот метод не является столь запоминающимся, как, например, системы ( «thecommand») или thecommand в обратных кавычках, хорошая вещь об этом методе по сравнению с другими методами .. это например, обратные кавычки, кажется, не дайте мне «путы 'команда бегает / сберегать команду я хочу запустить в переменном, и системе ( „thecommand“), кажется, не дайте мне получить выход. В то время как этот метод позволяет мне делать оба этих вещи, и это позволяет мне стандартный ввод доступа, стандартный вывод и стандартный поток ошибок независимо друг от друга.

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

Ответил 19/12/2017 d 05:54
источник пользователем

голоса
0

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

При использовании ТЗ 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()все будет всплывал , что раздражает окно при использовании ТЗ и rubyw.

Ответил 05/07/2018 d 12:55
источник пользователем

голоса
-1

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

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Ответил 14/10/2014 d 21:12
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more