code de sortie de contrôle de commande système ruby

106

J'ai un tas d'appels système dans ruby ​​tels que les suivants et je veux vérifier leurs codes de sortie simultanément afin que mon script se termine si cette commande échoue.

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

Je veux quelque chose comme

system("VBoxManage createvm --name test1", 0) <- où le deuxième paramètre vérifie le code de sortie et confirme que cet appel système a réussi, et sinon, il déclenchera une erreur ou fera quelque chose de ce genre.

Est-ce possible du tout?

J'ai essayé quelque chose du genre et cela n'a pas fonctionné non plus.

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
la source
2
duplication possible d' erreurs de ligne de commande Catching utilisant% x
Sergio Tulentsev
Dans l'exemple ci-dessus, exit_codesera une chaîne - soit "0\n"ou "1\n", donc exit_code != 0sera toujours vrai
dgmstuart

Réponses:

166

De la documentation :

le système renvoie truesi la commande donne un statut de sortie nul, falsepour un statut de sortie différent de zéro. Renvoie nilsi l'exécution de la commande échoue.

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

en outre

Un état d'erreur est disponible dans $?.

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

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2
Stefan
la source
2
et comment capturer sa sortie (pas le code de sortie) dans une variable?
ア レ ッ ク ス
Si vous êtes dans une console de rails et que vous testez cela, gardez à l'esprit que vous risquez de perdre la valeur de $? vous devez donc le capturer dans le cadre de votre commande 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
Une autre excellente comparaison de system, backticks, %xet execfournie ici: stackoverflow.com/questions/6338908/…
Tom Harrison
38

Pour moi, j'ai préféré utiliser `` pour appeler les commandes shell et vérifier $? pour obtenir le statut du processus. Le $? est un objet d'état de processus, vous pouvez obtenir les informations de processus de la commande à partir de cet objet, y compris: code d'état, état d'exécution, pid, etc.

Quelques méthodes utiles du $? objet:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
Houcheng
la source
1
Avec l'aide de Rubocop, j'ai découvert que l'alias lisible pour $?est$CHILD_STATUS
RajaRaviVarma
26

systemrenvoie falsesi la commande a un code de sortie différent de zéro, ou nils'il n'y a pas de commande.

Par conséquent

system( "foo" ) or exit

ou

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

devraient fonctionner et sont raisonnablement concis.

Neil Slater
la source
6

Vous ne capturez pas le résultat de votre systemappel, c'est là que le code de résultat est renvoyé:

exit_code = system("ruby test.rb")

Souvenez-vous que chaque systemappel ou équivalent, qui inclut la méthode backtick, génère un nouveau shell, il n'est donc pas possible de capturer le résultat de l'environnement d'un shell précédent. Dans ce cas , exit_codeest truesi tout a fonctionné, nilautrement.

La popen3commande fournit plus de détails de bas niveau.

tadman
la source
2
Open3.capture3est une méthode particulièrement simple à utiliser pour ce type de tâche.
the Tin Man
6

Une façon de le faire est de les chaîner en utilisant andou &&:

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

Le deuxième appel ne sera pas exécuté si le premier échoue.

Vous pouvez les envelopper dans un if ()pour vous donner un contrôle de flux:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
l'homme d'étain
la source
C'est jusqu'ici ce que je veux réaliser, assez simple et clair. Merci
mochadwi