Запуск команд командной строки в скрипте Ruby


92

Есть ли способ запускать команды командной строки через Ruby? Я пытаюсь создать небольшую программу Ruby, которая будет звонить и получать / отправлять через программы командной строки, такие как screen, rcsz и т. Д.

Было бы здорово, если бы я мог связать все это с Ruby (серверная часть MySQL и т. Д.)


Возможный дубликат команд Calling shell из Ruby
ymoreau

Ответы:


209

Да. Есть несколько способов:


а. Используйте %xили '' ':

%x(echo hi) #=> "hi\n"
%x(echo hi >&2) #=> "" (prints 'hi' to stderr)

`echo hi` #=> "hi\n"
`echo hi >&2` #=> "" (prints 'hi' to stderr)

Эти методы вернут stdout и перенаправят stderr в файл программы.


б. Использование system:

system 'echo hi' #=> true (prints 'hi')
system 'echo hi >&2' #=> true (prints 'hi' to stderr)
system 'exit 1' #=> nil

Этот метод возвращается, trueесли команда была успешной. Он перенаправляет весь вывод в программу.


c. Использование exec:

fork { exec 'sleep 60' } # you see a new process in top, "sleep", but no extra ruby process. 
exec 'echo hi' # prints 'hi'
# the code will never get here.

Это заменяет текущий процесс тем, который был создан командой.


d. (рубин 1.9) используйте spawn:

spawn 'sleep 1; echo one' #=> 430
spawn 'echo two' #=> 431
sleep 2
# This program will print "two\none".

Этот метод не ожидает завершения процесса и возвращает PID.


е. Использование IO.popen:

io = IO.popen 'cat', 'r+'
$stdout = io
puts 'hi'
$stdout = IO.new 0
p io.read(1)
io.close
# prints '"h"'.

Этот метод вернет IOобъект, который повторяет ввод / вывод новых процессов. Кроме того, в настоящее время это единственный известный мне способ ввести программу.


f. Использовать Open3(в 1.9.2 и новее)

require 'open3'

stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.successful?
  puts stdout
else
  STDERR.puts "OH NO!"
end

Open3имеет несколько других функций для получения явного доступа к двум выходным потокам. Он похож на popen, но дает вам доступ к stderr.


Бонус трюк: io = IO.popen 'cat > out.log', 'r+'; записывает выходные данные команды в "out.log"
Нарфанатор 03 июн.13,

1
Какие плюсы и минусы для каждого. Как мне решить, что использовать? Как насчет использования FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava

1
Я выполняю команду SVN с помощью exec. Я не хочу, чтобы вывод exec появлялся на консоли. Я хочу перенаправить его, чтобы я мог сохранить его как переменную и обработать его. Как мне это сделать ?
stack1

2
status.successful? у меня больше не работает на ruby ​​2.4, поменял на status.success? :)
DanielG 02

14

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

irb(main):003:0> `date /t` # surround with backticks
=> "Thu 07/01/2010 \n"
irb(main):004:0> system("date /t") # system command (returns true/false)
Thu 07/01/2010
=> true
irb(main):005:0> %x{date /t} # %x{} wrapper
=> "Thu 07/01/2010 \n"

Но если вам действительно нужно выполнять ввод и вывод с помощью команды stdin / stdout, вы, вероятно, захотите взглянуть на IO::popenметод, который специально предлагает эту возможность.


popen хорошо работает, если ваше приложение просто стандартно. Если вам нужно больше взаимодействия или вы хотите сделать что-то другое с помощью stdout, stdin и, в частности, stderr, вы также захотите изучить open3: ruby-doc.org/core/classes/Open3.html
Paul Rubel

7
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output

2

Да, это, конечно, выполнимо, но метод реализации отличается в зависимости от того, работает ли рассматриваемая программа «командной строки» в «полноэкранном» или в режиме командной строки. Программы, написанные для командной строки, обычно читают STDIN и записывают в STDOUT. Их можно вызывать непосредственно в Ruby, используя стандартные методы обратных кавычек и / или вызовы system / exec.

Если программа работает в «полноэкранном» режиме, например screen или vi, то подход должен быть другим. Для таких программ вам следует искать Ruby-реализацию библиотеки "expect". Это позволит вам создать сценарий того, что вы ожидаете увидеть на экране и что отправлять, когда вы видите, что эти конкретные строки появляются на экране.

Это вряд ли лучший подход, и вам, вероятно, следует посмотреть на то, чего вы пытаетесь достичь, и найти для этого соответствующую библиотеку / драгоценный камень, а не пытаться автоматизировать существующее полноэкранное приложение. В качестве примера « Требуется помощь в связи через последовательный порт в Ruby » рассматривается связь через последовательный порт, предварение набора номера, если это то, чего вы хотите достичь с помощью конкретных программ, которые вы упомянули.


Простая версия Expect доступна в Ruby с использованием встроенного модуля Pty .
Железный Человек

0

Наиболее часто используемый метод - Open3это моя отредактированная версия кода выше с некоторыми исправлениями:

require 'open3'
puts"Enter the command for execution"
some_command=gets
stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.success?
  puts stdout
else
  STDERR.puts "ERRRR"
end
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.