comando di sistema ruby ​​controlla il codice di uscita


106

Ho un sacco di chiamate di sistema in ruby ​​come le seguenti e voglio controllare i loro codici di uscita simultaneamente in modo che il mio script esca se quel comando fallisce.

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

Voglio qualcosa di simile

system("VBoxManage createvm --name test1", 0) <- dove il secondo parametro controlla il codice di uscita e conferma che quella chiamata di sistema ha avuto successo, e in caso contrario, solleverà un errore o farà qualcosa del genere.

È possibile?

Ho provato qualcosa sulla falsariga di questo e nemmeno quello ha funzionato.

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

o

`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
  raise 'Exit code is not zero'
end


Nell'esempio sopra, exit_codesarà una stringa - o "0\n"o "1\n", quindi exit_code != 0sarà sempre vero
dgmstuart

Risposte:


166

Dalla documentazione :

il sistema ritorna truese il comando fornisce uno stato di uscita zero, falseper uno stato di uscita diverso da zero. Restituisce nilse l'esecuzione del comando fallisce.

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

inoltre

Uno stato di errore è disponibile in $?.

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

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2

2
e come catturarne l'output (non il codice di uscita) in una variabile?
ア レ ッ ク ス

Se ti trovi in ​​una console rails e lo stai provando, tieni presente che potresti perdere il valore di $? quindi devi catturarlo come parte del tuo 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

Un altro eccellente confronto di system, backtick %xe execfornito qui: stackoverflow.com/questions/6338908/…
Tom Harrison

38

Per me, ho preferito usare `` per chiamare i comandi della shell e controllare $? per ottenere lo stato del processo. Il $? è un oggetto di stato del processo, è possibile ottenere le informazioni sul processo del comando da questo oggetto, inclusi: codice di stato, stato di esecuzione, pid, ecc.

Alcuni metodi utili del $? oggetto:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid

1
Con l'aiuto di Rubocop, ho scoperto che l'alias leggibile per $?è$CHILD_STATUS
RajaRaviVarma

26

systemrestituisce falsese il comando ha un codice di uscita diverso da zero onil se non è presente alcun comando.

Perciò

system( "foo" ) or exit

o

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

dovrebbero funzionare e sono ragionevolmente concisi.


6

Non stai catturando il risultato della tua systemchiamata, che è dove viene restituito il codice del risultato:

exit_code = system("ruby test.rb")

Ricorda che ogni systemchiamata o equivalente, che include il metodo backtick, genera una nuova shell, quindi non è possibile catturare il risultato dell'ambiente di una shell precedente. In questo caso exit_codeè truese tutto ha funzionato,nil altrimenti.

Il popen3comando fornisce dettagli di basso livello.


2
Open3.capture3è un metodo particolarmente facile da usare per questo tipo di attività.
Tin Man

6

Un modo per farlo è concatenarli usando ando &&:

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

La seconda chiamata non verrà eseguita se la prima non riesce.

Puoi avvolgerli in un if ()per darti un po 'di controllo del flusso:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end

Questo è finora quello che voglio ottenere, abbastanza semplice e chiaro. Grazie
mochadwi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.