Хотя этот вопрос полезен, он не очень хорошо задан. В Ruby есть много способов вызова вложенных оболочек, которые хорошо документированы и легко найдены, прочитав документацию по Kernel и Open3 и выполнив поиск здесь в SO.
Оловянный Человек
1
К сожалению, эта тема довольно сложная. Open3( docs ) - лучший выбор для большинства ситуаций, IMO, но в старых версиях Ruby он не учитывает измененные PATH( bugs.ruby-lang.org/issues/8004 ) и зависит от того, как вы передаете аргументы (в частности, , если вы используете хэш opts с не ключевыми словами), он может сломаться. Но если вы попадаете в такие ситуации, вы делаете что-то довольно продвинутое, и вы можете понять, что делать, прочитав реализацию Open3.
Джошуа Чик
3
Я удивлен, что никто не упомянул Shellwords.escape( док ). Вы не хотите вставлять пользовательский ввод непосредственно в команды оболочки - сначала удалите его! Смотрите также командный впрыск .
Кельвин
Ответы:
1319
Это объяснение основано на комментируемом сценарии Ruby от моего друга. Если вы хотите улучшить скрипт, обновите его по ссылке.
Во-первых, обратите внимание, что когда Ruby вызывает оболочку, он обычно вызывает /bin/sh, а не Bash. Некоторый синтаксис Bash поддерживается не /bin/shво всех системах.
Вот способы выполнить скрипт оболочки:
cmd ="echo 'hi'"# Sample string that can be used
Kernel#` обычно называют backticks - `cmd`
Это похоже на многие другие языки, включая Bash, PHP и Perl.
Возвращает результат (т.е. стандартный вывод) команды оболочки.
За xсимволом следует разделитель, которым может быть любой символ. Если разделитель является одним из символов (, [, {или <, в буквальном смысле состоит из символов , до закрытия соответствия разделителя, с учетом вложенных пар разделителей. Для всех других разделителей литерал содержит символы до следующего вхождения символа разделителя. Строковая интерполяция #{ ... }разрешена.
Возвращает результат (то есть стандартный вывод) команды оболочки, так же как обратные пометки.
exec("echo 'hi'")exec( cmd )# Note: this will never be reached because of the line above
Вот несколько дополнительных советов:
$?аналогично $CHILD_STATUSдоступу к состоянию последней команды, выполненной системой, если вы используете обратные галочки, system()или %x{}. Вы можете получить доступ к exitstatusи pidсвойства:
Мне нужно записать результаты моего исполняемого файла на производственном сервере, но не нашел пути. Я использовал #{cmd}put и logger.info ( #{cmd}). Есть ли способ зарегистрировать свои выходы на производстве?
Для полноты (как я сначала подумал, это также будет команда Ruby): Rake имеет sh, который выполняет команду «Выполнить системную команду cmd. Если задано несколько аргументов, команда не запускается с оболочкой (семантика та же, что и у Kernel ::». exec и Kernel :: system) ".
sschuberth
40
Обратные пометки не захватывают STDERR по умолчанию. Добавьте `2> & 1` в команду, если хотите захватить
Андрей Боталов
14
Я думаю, что этот ответ был бы немного улучшен, если бы он сказал, что обратные пометки и% x вернули «результат», а не «результат» данной команды. Последний может быть ошибочно принят за статус выхода. Или это только я?
Вау хаха Очень полезно, хотя тот факт, что это должно существовать, вызывает сожаление
Джош Бода
В качестве примечания, я нахожу метод spawn (), найденный во многих разных местах (например, Kernelи Processнаиболее универсальным. Он более или менее такой же PTY.spawn(), но более общий)
Смарт,
160
Мне нравится делать это, используя %xлитерал, который позволяет легко (и удобно читать) использовать кавычки в команде, например так:
directorylist =%x[find .-name '*test.rb'| sort]
Который, в этом случае, заполнит список файлов всеми тестовыми файлами в текущем каталоге, который вы можете обработать, как ожидается:
directorylist.each do|filename|
filename.chomp!# work with fileend
вышеупомянутое не работает для меня. `` <main> ': неопределенный метод, each' for :String (NoMethodError) как он работал для вас? Я использую ruby -v ruby 1.9.3p484 (2013-11-22 revision 43786) [i686-linux]Вы уверены, что массив возвращается из команды, чтобы цикл действительно работал?
Есть ли в Ruby std-lib документация о том, как выполнять Spec и модульное тестирование с помощью Open3 или других Open? На моем нынешнем уровне понимания сложно протестировать оболочки.
FilBot3
29
При выборе между этими механизмами необходимо учитывать следующие факторы:
Вы просто хотите использовать стандартный вывод или вам тоже нужен стандартный вывод? Или даже выделены?
Насколько велика ваша продукция? Вы хотите сохранить весь результат в памяти?
Вы хотите прочитать некоторые из ваших выводов, пока подпроцесс еще работает?
Вам нужны коды результатов?
Вам нужен объект Ruby, который представляет процесс и позволяет вам убивать его по требованию?
Возможно , вам что - нибудь из простых обратных кавычек ( ``), system()и IO.popenв полномасштабный Kernel.fork/ Kernel.execс IO.pipeи IO.select.
Вы также можете добавить тайм-ауты в микс, если подпроцесс занимает слишком много времени для выполнения.
Если вам действительно нужен Bash, то обратите внимание на «лучший» ответ.
Во-первых, обратите внимание, что когда Ruby вызывает оболочку, он обычно вызывает /bin/sh, а не Bash. Некоторый синтаксис Bash поддерживается не /bin/shво всех системах.
Если вам нужно использовать Bash, вставьте bash -c "your Bash-only command"внутрь желаемого метода вызова:
Вы также можете использовать операторы backtick (`), аналогичные Perl:
directoryListing =`ls /`
puts directoryListing # prints the contents of the root directory
Удобно, если вам нужно что-то простое.
Какой метод вы хотите использовать, зависит от того, что именно вы пытаетесь достичь; проверьте документы для более подробной информации о различных методах.
Используя ответы здесь и связанные в ответе Михая, я собрал функцию, которая отвечает этим требованиям:
Аккуратно фиксирует STDOUT и STDERR, чтобы они не «просачивались», когда мой скрипт запускается из консоли.
Позволяет передавать аргументы в оболочку в виде массива, поэтому вам не нужно беспокоиться об экранировании.
Записывает состояние завершения команды, чтобы было ясно, когда произошла ошибка.
В качестве бонуса этот также будет возвращать STDOUT в тех случаях, когда команда оболочки успешно завершает работу (0) и помещает что-либо в STDOUT. Таким образом, он отличается от того system, который просто возвращаетtrue в таких случаях.
Кодекс следует. Конкретная функция system_quietly:
require'open3'classShellError<StandardError;end#actual function:def system_quietly(*cmd)
exit_status=nil
err=nilout=nilOpen3.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.valueendif exit_status.to_i >0
err = err.chomp if err
raiseShellError, err
elsifoutreturnout.chomp
elsereturntrueendend#calling it:begin
puts system_quietly('which','ruby')rescueShellError
abort "Looks like you don't have the `ruby` command. Odd."end#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"
Не забудьте spawnкоманду для создания фонового процесса для выполнения указанной команды. Вы даже можете дождаться его завершения, используя Processкласс и возвращаемое значение pid:
Kernel.spawn()кажется гораздо более универсальным, чем все другие варианты.
Кашьяп
6
Если у вас есть более сложный случай, чем общий случай, с которым невозможно справиться ``, то ознакомьтесь с Kernel.spawn() . Похоже, это наиболее универсальный / полнофункциональный инструмент, предоставляемый стандартным Ruby для выполнения внешних команд.
Вы можете использовать его для:
создать группы процессов (Windows).
перенаправлять ошибки, файлы / друг друга.
установить env vars, umask.
измените каталог перед выполнением команды.
установить ограничения ресурсов для процессора / данных / и т. д.
Делайте все, что можно сделать с другими вариантами в других ответах, но с большим количеством кода.
Документация 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 =>trueor0: 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.SeeProcess.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,...)ornot:close_others =>false: inherit fds (defaultfor system andexec):close_others =>true: dont inherit (defaultfor spawn and IO.popen)
require'open3'
a="attrib"Open3.popen3(a)do|stdin, stdout, stderr|
puts stdout.read
end
Я обнаружил, что хотя этот метод не так запоминающийся, как
system("thecommand")
или
`thecommand`
в обратном кавычках хорошая вещь в этом методе по сравнению с другими методами в том, что обратные кавычки не позволяют мне putsвводить / сохранять команду, которую я хочу запустить в переменной, иsystem("thecommand") , похоже, не позволяют мне получить вывод, тогда как этот метод позволяет мне делать обе эти вещи, и он позволяет мне получать доступ к stdin, stdout и stderr независимо.
Это не совсем ответ, но, возможно, кто-то найдет его полезным:
При использовании TK GUI в Windows, и вам нужно вызывать команды оболочки из rubyw, у вас всегда будет раздражающее окно CMD, появляющееся менее чем за секунду.
Вот классный пример, который я использую в скрипте ruby на OS X (чтобы я мог запустить скрипт и получить обновление даже после переключения из окна):
cmd =%Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Open3
( docs ) - лучший выбор для большинства ситуаций, IMO, но в старых версиях Ruby он не учитывает измененныеPATH
( bugs.ruby-lang.org/issues/8004 ) и зависит от того, как вы передаете аргументы (в частности, , если вы используете хэш opts с не ключевыми словами), он может сломаться. Но если вы попадаете в такие ситуации, вы делаете что-то довольно продвинутое, и вы можете понять, что делать, прочитав реализациюOpen3
.Shellwords.escape
( док ). Вы не хотите вставлять пользовательский ввод непосредственно в команды оболочки - сначала удалите его! Смотрите также командный впрыск .Ответы:
Это объяснение основано на комментируемом сценарии Ruby от моего друга. Если вы хотите улучшить скрипт, обновите его по ссылке.
Во-первых, обратите внимание, что когда Ruby вызывает оболочку, он обычно вызывает
/bin/sh
, а не Bash. Некоторый синтаксис Bash поддерживается не/bin/sh
во всех системах.Вот способы выполнить скрипт оболочки:
Kernel#`
обычно называют backticks -`cmd`
Это похоже на многие другие языки, включая Bash, PHP и Perl.
Возвращает результат (т.е. стандартный вывод) команды оболочки.
Документы: http://ruby-doc.org/core/Kernel.html#method-i-60
Встроенный синтаксис,
%x( cmd )
За
x
символом следует разделитель, которым может быть любой символ. Если разделитель является одним из символов(
,[
,{
или<
, в буквальном смысле состоит из символов , до закрытия соответствия разделителя, с учетом вложенных пар разделителей. Для всех других разделителей литерал содержит символы до следующего вхождения символа разделителя. Строковая интерполяция#{ ... }
разрешена.Возвращает результат (то есть стандартный вывод) команды оболочки, так же как обратные пометки.
Документы: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-Percent+Strings
Kernel#system
Выполняет данную команду в подоболочке.
Возвращает,
true
если команда была найдена и успешно выполнена, вfalse
противном случае.Документы: http://ruby-doc.org/core/Kernel.html#method-i-system
Kernel#exec
Заменяет текущий процесс, выполнив данную внешнюю команду.
Не возвращает ничего, текущий процесс заменяется и никогда не продолжается.
Документы: http://ruby-doc.org/core/Kernel.html#method-i-exec
Вот несколько дополнительных советов:
$?
аналогично$CHILD_STATUS
доступу к состоянию последней команды, выполненной системой, если вы используете обратные галочки,system()
или%x{}
. Вы можете получить доступ кexitstatus
иpid
свойства:Для получения дополнительной информации см .:
источник
#{cmd}
put и logger.info (#{cmd}
). Есть ли способ зарегистрировать свои выходы на производстве?cmd
. Если задано несколько аргументов, команда не запускается с оболочкой (семантика та же, что и у Kernel ::». exec и Kernel :: system) ".Вот блок-схема, основанная на « Когда использовать каждый метод запуска подпроцесса в Ruby ». Смотрите также: « Обманите приложение, думая, что его стандартный вывод - это терминал, а не канал ».
источник
Kernel
иProcess
наиболее универсальным. Он более или менее такой жеPTY.spawn()
, но более общий)Мне нравится делать это, используя
%x
литерал, который позволяет легко (и удобно читать) использовать кавычки в команде, например так:Который, в этом случае, заполнит список файлов всеми тестовыми файлами в текущем каталоге, который вы можете обработать, как ожидается:
источник
%x[ cmd ]
возвращает массив для вас?each' for :String (NoMethodError)
как он работал для вас? Я используюruby -v ruby 1.9.3p484 (2013-11-22 revision 43786) [i686-linux]
Вы уверены, что массив возвращается из команды, чтобы цикл действительно работал?Вот лучшая на мой взгляд статья о запуске сценариев оболочки в Ruby: « 6 способов запуска команд оболочки в Ruby ».
Если вам нужно только получить выходные данные, используйте обратные метки.
Мне нужны были более продвинутые вещи, такие как STDOUT и STDERR, поэтому я использовал камень Open4. У вас есть все методы, объясненные там.
источник
%x
опцию синтаксиса.spawn
метода, когда нашел это.Мой любимый это Open3
источник
stdout, stderr, status = Open3.capture3('nroff -man', :stdin_data => stdin)
При выборе между этими механизмами необходимо учитывать следующие факторы:
Возможно , вам что - нибудь из простых обратных кавычек ( ``),
system()
иIO.popen
в полномасштабныйKernel.fork
/Kernel.exec
сIO.pipe
иIO.select
.Вы также можете добавить тайм-ауты в микс, если подпроцесс занимает слишком много времени для выполнения.
К сожалению, это очень многое зависит .
источник
Еще один вариант:
Когда ты:
Вы можете использовать перенаправление оболочки:
2>&1
Синтаксис работает через Linux , Mac и Windows , начиная с первых дней в MS-DOS.источник
Я определенно не эксперт по Ruby, но я попробую:
Вы также должны быть в состоянии сделать такие вещи, как:
источник
Ответы выше уже довольно хороши, но я действительно хочу поделиться следующей сводной статьей: « 6 способов запуска команд оболочки в Ruby »
В основном это говорит нам:
Kernel#exec
:system
и$?
:Backticks (`):
IO#popen
:Open3#popen3
- stdlib:Open4#popen4
-- драгоценный камень:источник
Если вам действительно нужен Bash, то обратите внимание на «лучший» ответ.
Если вам нужно использовать Bash, вставьте
bash -c "your Bash-only command"
внутрь желаемого метода вызова:Тестировать:
Или, если вы используете существующий файл сценария, как
Руби должен соблюдать шебанг, но вы всегда можете использовать
чтобы убедиться, что при
/bin/sh
запуске могут быть небольшие накладные расходы/bin/bash
, вы, вероятно, этого не заметите.источник
Вы также можете использовать операторы backtick (`), аналогичные Perl:
Удобно, если вам нужно что-то простое.
Какой метод вы хотите использовать, зависит от того, что именно вы пытаетесь достичь; проверьте документы для более подробной информации о различных методах.
источник
Мы можем достичь этого несколькими способами.
Используя
Kernel#exec
, ничего после этой команды не выполняется:С помощью
backticks or %x
Использование
Kernel#system
команды возвращает вtrue
случае успеха,false
если не удалось, и возвращает вnil
случае сбоя выполнения команды:источник
Самый простой способ, например:
источник
Используя ответы здесь и связанные в ответе Михая, я собрал функцию, которая отвечает этим требованиям:
В качестве бонуса этот также будет возвращать STDOUT в тех случаях, когда команда оболочки успешно завершает работу (0) и помещает что-либо в STDOUT. Таким образом, он отличается от того
system
, который просто возвращаетtrue
в таких случаях.Кодекс следует. Конкретная функция
system_quietly
:источник
Не забудьте
spawn
команду для создания фонового процесса для выполнения указанной команды. Вы даже можете дождаться его завершения, используяProcess
класс и возвращаемое значениеpid
:Док говорит: «Этот метод похож на,
#system
но он не ждет завершения команды.источник
Kernel.spawn()
кажется гораздо более универсальным, чем все другие варианты.Если у вас есть более сложный случай, чем общий случай, с которым невозможно справиться
``
, то ознакомьтесь сKernel.spawn()
. Похоже, это наиболее универсальный / полнофункциональный инструмент, предоставляемый стандартным Ruby для выполнения внешних команд.Вы можете использовать его для:
Документация Ruby имеет достаточно хороших примеров:
источник
Метод backticks (`) является самым простым для вызова команд оболочки из Ruby. Возвращает результат команды оболочки:
источник
Дана команда типа
attrib
:Я обнаружил, что хотя этот метод не так запоминающийся, как
или
в обратном кавычках хорошая вещь в этом методе по сравнению с другими методами в том, что обратные кавычки не позволяют мне
puts
вводить / сохранять команду, которую я хочу запустить в переменной, иsystem("thecommand")
, похоже, не позволяют мне получить вывод, тогда как этот метод позволяет мне делать обе эти вещи, и он позволяет мне получать доступ к stdin, stdout и stderr независимо.См. « Выполнение команд в ruby » и документацию по Ruby для Open3 .
источник
Это не совсем ответ, но, возможно, кто-то найдет его полезным:
При использовании TK GUI в Windows, и вам нужно вызывать команды оболочки из rubyw, у вас всегда будет раздражающее окно CMD, появляющееся менее чем за секунду.
Чтобы избежать этого, вы можете использовать:
или
Оба будут хранить
ipconfig
вывод внутриlog.txt
, но окна не появятся.Вам нужно будет
require 'win32ole'
внутри вашего сценария.system()
,exec()
иspawn()
будет все всплывающие окна , что раздражает при использовании ТЗ и rubyw.источник
Вот классный пример, который я использую в скрипте ruby на OS X (чтобы я мог запустить скрипт и получить обновление даже после переключения из окна):
источник