2017-02-14 5 views
3

Je souhaite savoir si des commandes d'un script bash sont sorties avec un statut différent de zéro.Comment savoir si une commande du script bash a échoué (état de sortie différent de zéro)

Je veux quelque chose de similaire à la fonctionnalité set -e, sauf que je ne veux pas qu'il se ferme lorsqu'une commande se termine avec un statut différent de zéro. Je veux exécuter le script entier, et je veux savoir que ce soit:

a) toutes les commandes avec le statut de sortis sortie 0
-ou-
b) une ou plusieurs commandes avec un liquide' non nul état


par exemple, étant donné les éléments suivants:

#!/bin/bash 

command1 # exits with status 1 
command2 # exits with status 0 
command3 # exits with status 0 

Je veux les trois commandes à exécuter. Après l'exécution du script, je veux une indication qu'au moins l'une des commandes est sortie avec un statut différent de zéro.

Répondre

1

tendre un piège sur ERR:

#!/bin/bash 

err=0 
trap 'err=1' ERR 

command1 
command2 
command3 
test $err = 0 # Return non-zero if any command failed 

Vous pourriez même jeter un peu d'introspection pour obtenir des données sur l'endroit où l'erreur est survenue:

#!/bin/bash 
for i in 1 2 3; do 
     eval "command$i() { echo command$i; test $i != 2; }" 
done 

err=0 
report() { 
     err=1 
     echo -n "error at line ${BASH_LINENO[0]}, in call to " 
     sed -n ${BASH_LINENO[0]}p $0 
} >&2 
trap report ERR 

command1 
command2 
command3 
exit $err 
+0

Parfait, exactement ce que je cherchais! Merci @William_Pursell! –

0

Vous avez la variable magique $? disponible en bash qui indique le code de sortie de la dernière commande:

#!/bin/bash 

command1 # exits with status 1 
C1_output=$? # will be 1 
command2 # exits with status 0 
C2_output=$? # will be 0 
command3 # exits with status 0 
C3_output=$? # will be 0 
+0

Oui, je suis conscient de cela. Cela ne répond pas directement à ma question. Vous pourriez supposer que je pourrais modifier le script pour garder un total de tous les états de sortie. Ce serait une solution, mais pas une solution souhaitable, car il faut ajouter 30 lignes de code à un script contenant 30 commandes, ce qui rend la lecture plus difficile, et est sujet à l'erreur humaine en oubliant de l'ajouter à toutes les commander. Je suppose que l'on pourrait créer une fonction et passer chaque commande à la fonction. Encore plutôt encombrant. J'espère quelque chose comme un simple type de solution 'set -e'. –

+0

@RobBednark C'est probablement ce que vous pouvez faire de mieux. Considérons une commande comme '((x = 0))'. C'est techniquement une commande échouée, parce que l'expression contenue évalue à 0. Tout automatisé devrait tenir compte de ce genre de choses. Le problème avec 'set -e' est qu'une commande échouée n'est pas nécessairement une erreur. – chepner

1

Je ne sais pas s'il y a une solution prête pour vos besoins. Je voudrais écrire une fonction comme ceci:

function run_cmd_with_check() { 
    "[email protected]" 
    [[ $? -ne 0 ]] && ((non_zero++)) 
} 

Ensuite, utilisez la fonction pour exécuter toutes les commandes qui ont besoin de suivi:

run_cmd_with_check command1 
run_cmd_with_check command2 
run_cmd_with_check command3 
printf "$non_zero commands exited with non-zero exit code\n" 

Si nécessaire, la fonction peut être améliorée pour stocker toutes les commandes échoué dans un tableau qui peut être imprimé à la fin.


Vous pouvez jeter un oeil à ce poste pour plus d'informations: Error handling in Bash

+0

@GrishaLevit - vous avez raison - j'ai corrigé la réponse. On dirait que le sujet de citations ne cesse d'être un peu confus ... – codeforester

0

Pour chaque commande, vous pouvez le faire:

if ! Command1 ; then an_error=1; fi 

Et répéter cette opération pour toutes les commandes

A la fin, an_error sera 1 si l'un d'entre eux a échoué.

Si vous souhaitez connaître le nombre d'échecs, définissez an_error sur 0 au début et faites $ ((an_error ++)). Au lieu de an_error = 1

0

Vous pouvez placer votre liste de commandes dans un tableau, puis passer en boucle sur les commandes. Tous ceux qui renvoient un code d'erreur conservent les résultats pour les consulter plus tard.

declare -A results 

commands=("your" "commands") 

for cmd in "${commands[@]}"; do 
    out=$($cmd 2>&1) 
    [[ $? -eq 0 ]] || results[$cmd]="$out" 
done  

Alors pour voir tous les codes non zéro de sortie:

for cmd in "${!results[@]}"; do echo "$cmd = ${results[$cmd]}"; done 

Si la longueur de results est 0, il n'y avait pas d'erreur sur votre liste de commandes.

Cela nécessite Bash 4+ (pour le tableau associatif)

3

Vous pouvez essayer de faire quelque chose avec un piège pour la DEBUG pseudosignal, comme

trap '(($? && ++errcount))' DEBUG 

Le piège DEBUG est exécuté « avant chaque commande simple, for commande, case commande, select commande, chaque commande arithmétique for, et avant que la première commande s'exécute dans une fonction shell "(citation du manuel).

Donc, si vous ajoutez ce piège et que la dernière chose commande pour imprimer le nombre d'erreurs, vous obtenez la valeur appropriée:

#!/bin/bash 

trap '(($? && ++errcount))' DEBUG 

true 
false 
true 

echo "Errors: $errcount" 

retours Errors: 1 et

#!/bin/bash 

trap '(($? && ++errcount))' DEBUG 

true 
false 
true 
false 

echo "Errors: $errcount" 

imprime Errors: 2. Attention, cette dernière instruction est en fait nécessaire pour prendre en compte la seconde false parce que le déroutement est exécuté avant les commandes, donc le statut de sortie pour le second false n'est vérifié que lorsque l'interruption de la ligne echo est exécutée.

0

Vous pouvez utiliser le piège DEBUG comme:

trap 'code+=$?' DEBUG 
code=0 

# run commands here normally 

exit $code