código de saída de verificação de comando do sistema ruby

106

Eu tenho um monte de chamadas de sistema em ruby, como a seguir, e quero verificar seus códigos de saída simultaneamente para que meu script saia se o comando falhar.

system("VBoxManage createvm --name test1")
system("ruby test.rb")

Eu quero algo como

system("VBoxManage createvm --name test1", 0) <- onde o segundo parâmetro verifica o código de saída e confirma que a chamada do sistema foi bem-sucedida e, se não, gerará um erro ou fará algo desse tipo.

Isso é sequer possível?

Tentei algo parecido com isso e também não funcionou.

system("ruby test.rb")
system("echo $?")

ou

`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
  raise 'Exit code is not zero'
end
user1530318
fonte
2
possível duplicata de Captura de erros de linha de comando usando% x
Sergio Tulentsev
No exemplo acima, exit_codeserá uma string - "0\n"ou "1\n", então exit_code != 0sempre será verdadeiro
dgmstuart

Respostas:

166

Da documentação :

o sistema retorna truese o comando der status de saída zero, falsepara status de saída diferente de zero Retorna nilse a execução do comando falhar.

system("unknown command")     #=> nil
system("echo foo")            #=> true
system("echo foo | grep bar") #=> false

além disso

Um status de erro está disponível em $?.

system("VBoxManage createvm --invalid-option")

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2
Stefan
fonte
2
e como capturar sua saída (não o código de saída) para uma variável?
ア レ ッ ク ス
Se você estiver em um console Rails, testando isso, lembre-se de que você pode perder o valor de $? então você precisa capturá-lo como parte do seu comando REPL [10] pry(main)> system("touch /root/test 2> /dev/null") => false [11] pry(main)> $?.exitstatus => 0 [12] pry(main)> system("touch /root/test 2> /dev/null"); $?.exitstatus => 1
lardcanoe
Outra excelente comparação de systembackticks, %xe execfornecida aqui: stackoverflow.com/questions/6338908/…
Tom Harrison
38

Para mim, preferi usar `` para chamar os comandos do shell e verificar $? para obter o status do processo. O $? é um objeto de status do processo, você pode obter as informações do processo do comando a partir deste objeto, incluindo: código de status, status de execução, pid, etc.

Alguns métodos úteis do $? objeto:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
Houcheng
fonte
1
Com a ajuda do Rubocop, descobri que o alias legível para $?é$CHILD_STATUS
RajaRaviVarma
26

systemretorna falsese o comando tiver um código de saída diferente de zero ou nilse não houver comando.

Portanto

system( "foo" ) or exit

ou

system( "foo" ) or raise "Something went wrong with foo"

devem funcionar e são razoavelmente concisos.

Neil Slater
fonte
6

Você não está capturando o resultado da sua systemchamada, que é onde o código do resultado é retornado:

exit_code = system("ruby test.rb")

Lembre-se de que cada systemchamada ou equivalente, que inclui o método backtick, gera um novo shell, portanto, não é possível capturar o resultado de um ambiente de shell anterior. Nesse caso, exit_codeé truese tudo deu certo, nilcaso contrário.

O popen3comando fornece mais detalhes de baixo nível.

Tadman
fonte
2
Open3.capture3é um método particularmente fácil de usar para esse tipo de tarefa.
O Homem de Lata de
6

Uma maneira de fazer isso é encadeá-los usando andou &&:

system("VBoxManage createvm --name test1") and system("ruby test.rb")

A segunda chamada não será executada se a primeira falhar.

Você pode envolvê-los em um if ()para obter algum controle de fluxo:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
o homem de lata
fonte
Isso é o que eu quero alcançar, direto e claro o suficiente. Obrigado
mochadwi