Se quiser correr um comando externo a partir de Ruby…
…como wkhtmltopdf para converter um ficheiro HTML para um PDF.
Existem alguns métodos Ruby que pode utilizar.
Dependente do método que utilizar irá obter resultados diferentes.
Vamos explorar estes métodos em conjunto!
O método do sistema Ruby
O método do sistema Ruby é a forma mais simples de executar um comando externo.
Parecido com isto:
system("ls")
Note que system
irá imprimir a saída do comando à medida que ele acontece.
O sistema também fará o seu programa Ruby esperar até que o comando seja feito.
Tente isto:
system("sleep 2")
Existem formas de executar comandos em segundo plano como veremos mais à frente.
System can return 3 possible values:
-
true
if the command worked -
false
if the command returns an error code -
nil
if command execution fails (command not found)
You can get the exit status code of the last external command that you ran with the $?
global variable. Este código de estado pode dar-lhe mais informação sobre a razão pela qual o comando falhou.
O que é a expansão da shell?
Quando correr um comando externo com system
obterá o efeito “expansão da shell”.
Expansão da shell é quando a shell (sh/bash/zsh) leva alguns caracteres especiais (*
, ?
, e ")# "best"
This will not change the current environment of your Ruby application.
%x / Kernel#`
If you want to get the output from the command you're running, instead of displaying it then you can use %x
ou o método Kernel#`
.
Fazem a mesma coisa.
Aqui está um exemplo:
`ls`
Outro com %x
:
%x|ls|
Estes dois exemplos retornarão uma string com a saída do comando ls
.
Note que você ainda tem que esperar que o comando termine a menos que você o execute dentro de uma thread.
Como usar o Fork + Exec para executar comandos externos num processo separado
Forking faz uma cópia do seu processo actual (a sua aplicação Ruby) então pode substituir essa cópia por outro processo usando exec.
Nota: O método fork não está disponível no Windows.
Este é um padrão popular no mundo Unix.
Aí está como ele funciona:
fork { exec("ls") }
Este irá correr ls
noutro processo & mostrar a sua saída.
Porque este comando está a correr noutro processo não irá bloquear a sua aplicação Ruby de correr como o método system
ou %x
.
Important:
Se você usar exec
sem fork
você vai substituir seu processo atual.
Isto significa que seu programa Ruby irá terminar.
Como usar o método Popen para comunicação bidireccional com um programa externo
Se precisar:
- Mais controlo sobre o processo
- Comunicação bidireccional
Então o método IO.popen
é o que procura.
No exemplo seguinte eu uso o método popen para iniciar um processo irb
, depois enviar alguma entrada para ele & ler a saída.
Aqui o exemplo:
r = IO.popen("irb", "r+")r.write "puts 123 + 1\n"3.times { puts r.gets }r.write "exit\n"
Esta r
variável é um objeto IO, isto significa que você pode escrever & ler a partir dele como um arquivo normal.
Usando popen
também significa que o seu comando externo irá correr no seu próprio processo, para que não tenha de o correr numa thread.
Há também um método popen3
na biblioteca padrão.
A diferença com o regular popen
é que irá dividir a saída regular & mensagens de erro em objectos IO separados.
Conclusão
Você aprendeu sobre as diferentes maneiras de interagir com comandos externos em Ruby.
Tenha cuidado com estes!
Não passe nenhum tipo de entrada de usuário para estes comandos a menos que você queira um problema de segurança na sua aplicação Ruby.