código de salida de verificación del comando del sistema ruby

106

Tengo un montón de llamadas al sistema en ruby ​​como las siguientes y quiero verificar sus códigos de salida simultáneamente para que mi script salga si ese comando falla.

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

Quiero algo como

system("VBoxManage createvm --name test1", 0) <- donde el segundo parámetro verifica el código de salida y confirma que esa llamada al sistema fue exitosa, y si no, generará un error o hará algo por el estilo.

¿Es eso posible?

Intenté algo parecido a esto y tampoco funcionó.

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

o

`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
  raise 'Exit code is not zero'
end
usuario1530318
fuente
2
posible duplicado de la captura de errores de línea de comandos usando% x
Sergio Tulentsev
En el ejemplo anterior, exit_codeserá una cadena, ya sea "0\n"o "1\n", por exit_code != 0lo que siempre será cierto
dgmstuart

Respuestas:

166

De la documentación :

el sistema regresa truesi el comando da un estado de salida cero, falsepara un estado de salida distinto de cero. Devuelve nilsi falla la ejecución del comando.

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

además

Un estado de error está disponible en $?.

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

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2
Stefan
fuente
2
y cómo capturar su salida (no código de salida) a una variable?
ア レ ッ ク ス
Si está en una consola de rieles, probando esto, solo tenga en cuenta que puede perder el valor de $? por lo que debe capturarlo como parte de su 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
Otra excelente comparación de system, comillas invertidas, %xy se execproporciona aquí: stackoverflow.com/questions/6338908/…
Tom Harrison
38

Para mí, preferí usar '' para llamar a los comandos de shell y marcar $? para obtener el estado del proceso. El $? es un objeto de estado de proceso, puede obtener la información de proceso del comando de este objeto, que incluye: código de estado, estado de ejecución, pid, etc.

Algunos métodos útiles de $? objeto:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
Houcheng
fuente
1
Con la ayuda de Rubocop, descubrí que el alias legible para $?es$CHILD_STATUS
RajaRaviVarma
26

systemdevuelve falsesi el comando tiene un código de salida distinto de cero o nilsi no hay ningún comando.

Por lo tanto

system( "foo" ) or exit

o

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

deberían funcionar y son razonablemente concisas.

Neil Slater
fuente
6

No está capturando el resultado de su systemllamada, que es donde se devuelve el código de resultado:

exit_code = system("ruby test.rb")

Recuerde que cada systemllamada o equivalente, que incluye el método backtick, genera un nuevo shell, por lo que no es posible capturar el resultado del entorno de un shell anterior. En este caso exit_codees truesi todo salió bien, de lo nilcontrario.

El popen3comando proporciona más detalles de bajo nivel.

tadman
fuente
2
Open3.capture3es un método particularmente fácil de usar para este tipo de tarea.
The Tin Man
6

Una forma de hacer esto es encadenarlos usando ando &&:

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

La segunda llamada no se ejecutará si la primera falla.

Puede envolverlos en un if ()para darle un poco de control de flujo:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
el hombre de hojalata
fuente
Hasta ahora, esto es lo que quiero lograr, sencillo y lo suficientemente claro. Gracias
mochadwi