Comment vérifier si une commande a réussi?

235

Est-il possible de vérifier s'il y a une erreur dans l'exécution d'une commande?

Exemple :

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

J'ai déjà essayé de le faire mais il semble que cela ne fonctionne pas. Je ne sais pas comment faire ça.

moata_u
la source
9
Préférez $ (foo) aux backticks `foo` , parce que vous pouvez l'imbriquer et qu'il est plus facile de faire la distinction entre les apostrophes.
utilisateur inconnu
1
En passant, vous devez définir une fonction ( valid) avant de l’appeler.
Wjandrea

Réponses:

345

La valeur de retour est stockée dans $?. 0 indique un succès, d'autres indique une erreur.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Comme toute autre valeur textuelle, vous pouvez la stocker dans une variable pour une comparaison future:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

Pour les opérateurs de comparaison possibles, voir man test.

Lekensteyn
la source
C'est bien ... puis-je tenir l'erreur de sortie ?? !! , car dans ce cas j’ai 2 erreur: erreur de commande "text" ex, fichier non trouvé et mon erreur "text" qui est dans ce cas a échoué par exemple
moata_u
@moata_u: vous pouvez stocker la valeur dans une variable, comme indiqué dans ma réponse.
Lekensteyn
@moata_u: Vous devez mettre un ;avant le elseet fi: `if ...; puis ...; autre ...; fi
Lekensteyn
4
Ceci est une utilisation inutile detest .
David Foerster
1
@Blauhirn [ $? ](ou de manière équivalente test $?) ne fonctionne pas car il correspond $?à un nombre (0, 1, etc.) qui n'est pas nul. Voir la documentation pourtest : "Si EXPRESSION est omis, 'test' renvoie false. Si EXPRESSION est un argument unique, 'test' renvoie false si l'argument est null et true sinon."
Lekensteyn
87

Si vous avez seulement besoin de savoir si la commande a réussi ou échoué, ne testez pas $?, testez simplement la commande. Par exemple:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

Et assigner la sortie à une variable ne change pas la valeur de retour (enfin, sauf si cela se comporte différemment quand stdout n'est pas un terminal bien sûr).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals explique ifplus en détail.

geirha
la source
Que faire si vous voulez faire autre chose que créer une branche, comme stocker le booléen de savoir si elle a échoué ou non dans un fichier .ini? Ensuite, votre variable de sortie ne le fait pas, mais le $?fait. Vous avez donc tort de dire que tester directement la commande est strictement préférable.
Timothy Swan
L'affectation de la sortie à une variable peut modifier la valeur de retour lorsque l'on utilise la localcommande, c'est-à-dire local foo=$(false); echo $?;produit 0sur la sortie. Mais localn'est pertinent que dans les fonctions bash.
Cromax
26
command && echo OK || echo Failed
Abraham Sanchez
la source
Si l' commanderreur est renvoyée à l'écran, comment la masquer?
Sigur
Si commanddes erreurs sont écrites sur stderr, vous pouvez utiliser le formulaire command 2> /dev/null && echo OK || echo Failed. Les 2> /dev/nullredirections stderr en sortie /dev/null. Cependant, certains utilitaires écriront des erreurs sur stdout (même si c'est une mauvaise pratique). Dans ce cas, vous pouvez omettre le 2 de la redirection, mais vous perdrez toute sortie de la commande. Cette méthode de vérification de la réussite est utile pour une logique ternaire simple, mais pour un comportement plus complexe, il est préférable de vérifier la $?réussite de la commande ou d'utiliser la ifméthode de blocage décrite dans la réponse de @ geirha.
Bender the Greatest
17

$? doit contenir le statut de sortie de la commande précédente, qui doit être zéro pour aucune erreur.

Donc, quelque chose comme:

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

dans la plupart des cas, il est plus facile d'utiliser la construction && pour chaîner des commandes qui doivent dépendre les unes des autres. Donc, cd /nonexistant && echo success!ne pas écho à succès, car la commande rompt avant &&. Le corollaire est ||, où cd /nonexistant || echo fail serait l' écho échouer parce que cd a échoué. (cela devient utile si vous utilisez quelque chose comme || exit, qui mettra fin au script si la commande précédente a échoué.)

Shaun
la source
C'est bien ... puis-je tenir l'erreur de sortie ?? !! , car dans ce cas j’ai 2 erreur: erreur de commande "text" ex, fichier non trouvé et mon erreur "text" qui est dans ce cas a échoué par exemple
moata_u
@moata_u, voir mywiki.wooledge.org/BashFAQ/002
geirha
5
command && echo $? || echo $?
modrobert
la source
Tu veux dire command; echo $??
Javier Buzzi
Non, ma ligne est correcte, elle donne le code de résultat réel sous forme de numéro, que ce soit en cas de succès ou d’échec.
Modrobert
1
Ok, s'il vous plaît expliquer les différences de ces pour moi: true && echo $? || echo $?/ true; echo $?et false && echo $? || echo $?/ false; echo $?- vous trouverez, ils font exactement la même chose: D
Javier Buzzi
Oui, le même résultat mais sans la condition. La question initiale posée était "Comment vérifier si une commande a réussi?", Elle était basée sur les réponses précédentes. Je suppose qu'un meilleur exemple serait:command && echo "success: $?" || echo "fail: $?"
Modrobert
5

Il convient de noter que if...then...fiet &&/ ||type d’approche concerne l’état de sortie renvoyé par la commande à tester (0 en cas de succès); Cependant, certaines commandes ne renvoient pas de statut de sortie non nul si la commande échoue ou ne peut pas traiter les entrées. Cela signifie que les approches habituelles ifet &&/ ||ne fonctionneront pas pour ces commandes particulières.

Par exemple, sous Linux, GNU filese ferme toujours à 0 s'il a reçu un fichier non existant en argument et findne peut pas localiser le fichier spécifié par l'utilisateur.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

Dans de tels cas, une solution potentielle consiste à lire stderr/ les stdinmessages, par exemple ceux renvoyés par filecommande, ou à analyser le résultat de la commande comme dans find. À cette fin, une casedéclaration pourrait être utilisée.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

(Ceci est un report de ma propre réponse sur une question connexe à unix.stackexchange.com )

Sergiy Kolodyazhnyy
la source
1

Comme mentionné dans de nombreuses autres réponses, un simple test de $?va faire, comme ceci

if [ $? -eq 0 ]; then something; fi

Si vous voulez tester si la commande a échoué , vous pouvez utiliser une version plus courte dans bash(mais peut-être trop cher) comme suit:

if (($?)); then something; fi

Cela fonctionne en utilisant le (( ))mode de calcul, donc si la commande est retourné success, à savoir $? = 0le test évalue à ((0))qui teste comme false, sinon elle retournera true.

Pour tester le succès , vous pouvez utiliser:

if ! (($?)); then something; fi

mais ce n'est déjà pas beaucoup plus court que le premier exemple.

afuna
la source
1
critique constructive?
Afuna
-2

si [$ (commande)]; alors echo "réussir"; Fi

Amozejko
la source
3
trueréussit if [ $(true) ]; then echo "succeed"; fimais succeedn'est pas imprimé. En fait, cela ne vérifie jamais si cela a commandréussi. Il devrait juste utiliser if commandcomme dans le post de geirha . $( )est la substitution de commande . [ ]est une expression conditionnelle . En l'absence de fractionnement des mots et d'expansion du nom de fichier , cette option permet de vérifier si la commandsortie est correcte.
Eliah Kagan le