Executar comandos de linha de comando no script Ruby


92

Existe uma maneira de executar comandos de linha de comando através do Ruby? Estou tentando criar um pequeno programa Ruby que discaria e receberia / enviaria através de programas de linha de comando como 'screen', 'rcsz', etc.

Seria ótimo se eu pudesse ligar tudo isso com Ruby (back-end do MySQL, etc.)


Possível duplicata de comandos Calling shell de Ruby
ymoreau

Respostas:


209

Sim. Existem várias maneiras:


uma. Use %xou '`':

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

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

Esses métodos retornarão o stdout e redirecionarão o stderr para o do programa.


b. Use system:

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

Este método retorna truese o comando foi bem sucedido. Ele redireciona todas as saídas para o programa.


c. Use 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.

Isso substitui o processo atual pelo criado pelo comando.


d. (rubi 1.9) use spawn:

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

Este método não espera a saída do processo e retorna o PID.


e. Use IO.popen:

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

Este método retornará um IOobjeto que repercute a entrada / saída dos novos processos. Também é atualmente a única maneira que conheço de fornecer informações ao programa.


f. Use Open3(em 1.9.2 e posterior)

require 'open3'

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

Open3tem várias outras funções para obter acesso explícito aos dois fluxos de saída. É semelhante ao popen, mas dá acesso ao stderr.


Truque Bonus: io = IO.popen 'cat > out.log', 'r+'; grava as saídas do comando em "out.log"
Narfanator

1
Quais são os prós e os contras de cada um. Como decido qual usar? Que tal usar FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava

1
Estou executando um comando SVN usando exec. Não quero que a saída de exec apareça no console. Quero redirecioná-lo para que possa armazená-lo como uma variável e fazer algum processamento nisso. Como eu faço isso ?
pilha 1 de

2
status.successful? não está mais funcionando para mim no ruby ​​2.4, ele mudou para status.success? :)
DanielG

14

Existem algumas maneiras de executar comandos do sistema em 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"

Mas se você realmente precisar executar entrada e saída com o comando stdin / stdout, provavelmente desejará examinar o IO::popenmétodo, que oferece especificamente esse recurso.


popen funciona bem se o seu aplicativo tiver apenas saída padrão. Se você precisar de mais interação ou quiser fazer algo diferente com stdout, stdin e particularmente stderr, você também vai querer dar uma olhada em 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

Sim, certamente é possível, mas o método de implementação difere dependendo se o programa de "linha de comando" em questão opera em "Tela inteira" ou no modo de linha de comando. Programas escritos para a linha de comando tendem a ler STDIN e escrever em STDOUT. Eles podem ser chamados diretamente no Ruby usando os métodos de crase padrão e / ou chamadas de sistema / exec.

Se o programa opera no modo "Full Screen", como screen ou vi, a abordagem deve ser diferente. Para programas como esse, você deve procurar uma implementação Ruby da biblioteca "esperar". Isso permitirá que você crie um script do que espera ver na tela e o que enviar quando vir essas strings específicas aparecerem na tela.

Esta provavelmente não é a melhor abordagem e você provavelmente deve olhar o que está tentando alcançar e encontrar a biblioteca / gem relevante para fazer isso, em vez de tentar automatizar um aplicativo de tela inteira existente. Como um exemplo, " Preciso de ajuda com comunicações de porta serial em Ruby " lida com comunicações de porta serial, um pré-cursor para discagem se for isso que você deseja alcançar usando os programas específicos que mencionou.


Uma versão simples do Expect está disponível em Ruby usando seu módulo Pty integrado .
o Homem de Lata

0

O método mais usado está usando Open3aqui é minha versão editada do código acima com algumas correções:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.