Comment intercepter les erreurs dans les scripts Bash sous Linux
Par défaut, un script Bash sous Linux signalera une erreur mais continuera à s’exécuter. Nous vous montrons comment gérer vous-même les erreurs afin que vous puissiez décider de ce qui doit se passer ensuite.
Sommaire
Gestion des erreurs dans les scripts
La gestion des erreurs fait partie de la programmation. Même si vous écrivez un code sans faille, vous pouvez toujours rencontrer des conditions d’erreur. L’environnement de votre ordinateur change au fil du temps, à mesure que vous installez et désinstallez des logiciels, créez des répertoires et effectuez des mises à niveau et des mises à jour.
Par exemple, un script qui s’exécutait sans problème peut rencontrer des difficultés si les chemins de répertoire changent ou si les autorisations sont modifiées sur un fichier. L’action par défaut du shell Bash est d’afficher un message d’erreur et de continuer à exécuter le script. C’est un défaut dangereux.
Si l’action qui a échoué est critique pour un autre traitement ou action qui se produit plus tard dans votre script, cette action critique ne réussira pas. À quel point cela s’avère désastreux dépend de ce que votre script essaie de faire.
Un schéma plus robuste détecterait les erreurs et laisserait le script fonctionner s’il devait s’arrêter ou essayer de remédier à la condition de panne. Par exemple, si un répertoire ou un fichier manque, il peut être satisfaisant que le script les recrée.
Si le script a rencontré un problème dont il ne peut pas se remettre, il peut s’arrêter. Si le script doit s’arrêter, il peut avoir la possibilité d’effectuer tout nettoyage requis, comme la suppression de fichiers temporaires ou l’écriture de la condition d’erreur et de la raison de l’arrêt dans un fichier journal.
Détection du statut de sortie
Les commandes et les programmes génèrent une valeur qui est envoyée au système d’exploitation lorsqu’ils se terminent. C’est ce qu’on appelle leur statut de sortie. Il a une valeur de zéro s’il n’y a pas eu d’erreurs, ou une valeur différente de zéro si une erreur s’est produite.
Nous pouvons vérifier l’état de sortie, également appelé code de retour, des commandes utilisées par le script et déterminer si la commande a réussi ou non.
Dans Bash, zéro équivaut à vrai. Si la réponse de la commande est autre que vrai, nous savons qu’un problème s’est produit et nous pouvons prendre les mesures appropriées.
Copiez ce script dans un éditeur et enregistrez-le dans un fichier appelé « bad_command.sh ».
#!/bin/bash if ( ! bad_command ); then echo "bad_command flagged an error." exit 1 fi
Vous devrez rendre le script exécutable avec le chmod
commande. Il s’agit d’une étape nécessaire pour rendre n’importe quel script exécutable, donc si vous voulez essayer les scripts sur votre propre machine, n’oubliez pas de le faire pour chacun d’eux. Remplacez le nom du script approprié dans chaque cas.
chmod +x bad_command.sh
Lorsque nous exécutons le script, nous voyons le message d’erreur attendu.
./bad_command.sh
Il n’y a pas de commande telle que « bad_command », ni le nom d’une fonction dans le script. Il ne peut pas être exécuté, donc la réponse est ne pas zéro. Si la réponse n’est pas zéro, le point d’exclamation est utilisé ici comme point logique NOT
opérateur—le corps du if
l’instruction est exécutée.
Dans un script réel, cela pourrait terminer le script, ce que fait notre exemple, ou cela pourrait essayer de remédier à la condition d’erreur.
Cela pourrait ressembler à exit 1
ligne est redondante. Après tout, il n’y a rien d’autre dans le script et il va se terminer de toute façon. Mais en utilisant le exit
La commande nous permet de renvoyer un état de sortie au shell. Si jamais notre script est appelé depuis un second script, ce second script saura que ce script a rencontré des erreurs.
Vous pouvez utiliser la logique OR
opérateur avec le statut de sortie d’une commande, et appelez une autre commande ou une fonction dans votre script s’il y a une réponse non nulle de la première commande.
command_1 || command_2
Cela fonctionne car soit la première commande s’exécute OR
la deuxième. La commande la plus à gauche est exécutée en premier. Si elle réussit, la deuxième commande n’est pas exécutée. Mais si la première commande échoue, la deuxième commande est exécutée. Nous pouvons donc structurer le code comme celui-ci. C’est « logique-or./sh. »
#!/bin/bash error_handler() { echo "Error: ($?) $1" exit 1 } bad_command || error_handler "bad_command failed, Line: ${LINENO}"
Nous avons défini une fonction appelée error_handler
. Cela imprime l’état de sortie de la commande ayant échoué, contenu dans la variable $?
et une ligne de texte qui lui est transmise lorsque la fonction est appelée. Ceci est contenu dans la variable $1
. La fonction termine le script avec un état de sortie de un.
Le script essaie de s’exécuter bad_command
qui échoue évidemment, donc la commande à droite de la logique OR
opérateur, ||
, est exécuté. Cela appelle le error_handler
fonction et passe une chaîne qui nomme la commande qui a échoué et contient le numéro de ligne de la commande qui a échoué.
Nous allons exécuter le script pour voir le message du gestionnaire d’erreurs, puis vérifier l’état de sortie du script à l’aide de echo.
./logical-or.sh
echo $?
Notre petit error_handler
la fonction fournit l’état de sortie de la tentative d’exécution bad_command
, le nom de la commande et le numéro de ligne. Il s’agit d’informations utiles lorsque vous déboguez un script.
L’état de sortie du script est un. Le statut de sortie 127 signalé par error_handler
signifie « commande introuvable ». Si nous le voulions, nous pourrions l’utiliser comme état de sortie du script en le transmettant au exit
commande.
Une autre approche consisterait à étendre error_handler
pour vérifier les différentes valeurs possibles du statut de sortie et effectuer différentes actions en conséquence, en utilisant ce type de construction :
exit_code=$? if [ $exit_code -eq 1 ]; then echo "Operation not permitted" elif [ $exit_code -eq 2 ]; then echo "Misuse of shell builtins" . . . elif [ $status -eq 128 ]; then echo "Invalid argument" fi
Utiliser set pour forcer une sortie
Si vous savez que vous voulez que votre script se termine chaque fois qu’il y a une erreur, vous pouvez le forcer à le faire. cela signifie que vous renoncez à tout nettoyage – ou à tout autre dommage également – car votre script se termine dès qu’il détecte une erreur.
Pour ce faire, utilisez le set
commande avec le -e
option (erreur). Cela indique au script de se fermer chaque fois qu’une commande échoue ou renvoie un code de sortie supérieur à zéro. Aussi, en utilisant le -E
L’option garantit que la détection et le piégeage des erreurs fonctionnent dans les fonctions du shell.
Pour intercepter également les variables non initialisées, ajoutez le -u
(non défini). Pour vous assurer que les erreurs sont détectées dans les séquences canalisées, ajoutez le -o pipefail
option. Sans cela, l’état de sortie d’une séquence de commandes canalisée est l’état de sortie du final commande dans la séquence. Une commande défaillante au milieu de la séquence canalisée ne serait pas détectée. La -o pipefail
L’option doit figurer dans la liste des options.
La séquence à ajouter en haut de votre script est :
set -Eeuo pipefail
Voici un court script appelé « unset-var.sh », avec une variable non définie.
#!/bin/bash set -Eeou pipefail echo "$unset_variable" echo "Do we see this line?"
Lorsque nous exécutons le script, la unset_variable est reconnue comme une variable non initialisée et le script est terminé.
./unset-var.sh
La deuxième echo
la commande n’est jamais exécutée.
Utiliser le piège avec des erreurs
La commande Bash trap vous permet de désigner une commande ou une fonction qui doit être appelée lorsqu’un signal particulier est déclenché. Généralement, cela est utilisé pour capter des signaux tels que SIGINT
qui est déclenché lorsque vous appuyez sur la combinaison de touches Ctrl + C. Ce script est « sigint.sh ».
#!/bin/bash trap "echo -e 'nTerminated by Ctrl+c'; exit" SIGINT counter=0 while true do echo "Loop number:" $((++counter)) sleep 1 done
La trap
la commande contient un echo
commande et le exit
commande. Il sera déclenché lorsque SIGINT
est relevé. Le reste du script est une simple boucle. Si vous exécutez le script et appuyez sur Ctrl + C, vous verrez le message du trap
définition, et le script se terminera.
./sigint.sh
On peut utiliser trap
avec le ERR
signal pour détecter les erreurs au fur et à mesure qu’elles se produisent. Ceux-ci peuvent ensuite être transmis à une commande ou à une fonction. C’est « trap.sh ». Nous envoyons des notifications d’erreur à une fonction appelée error_handler
.
#!/bin/bash trap 'error_handler $? $LINENO' ERR error_handler() { echo "Error: ($1) occurred on $2" } main() { echo "Inside main() function" bad_command second third exit $? } second() { echo "After call to main()" echo "Inside second() function" } third() { echo "Inside third() function" } main
La majeure partie du script se trouve à l’intérieur du main
fonction, qui appelle la second
et third
les fonctions. Lorsqu’une erreur se produit, dans ce cas, parce que bad_command
n’existe pas – le trap
l’instruction dirige l’erreur vers error_handler
fonction. Il transmet l’état de sortie de la commande ayant échoué et le numéro de ligne au error_handler
fonction.
./trap.sh
Notre error_handler
La fonction répertorie simplement les détails de l’erreur dans la fenêtre du terminal. Si vous le souhaitez, vous pouvez ajouter un exit
commande à la fonction pour que le script se termine. Ou vous pouvez utiliser une série de if/elif/fi
instructions pour effectuer différentes actions pour différentes erreurs.
Il peut être possible de corriger certaines erreurs, d’autres peuvent nécessiter l’arrêt du script.
Un dernier conseil
Détecter les erreurs signifie souvent anticiper les choses qui peuvent mal tourner et mettre en place du code pour gérer ces éventualités si elles se présentent. C’est en plus de s’assurer que le flux d’exécution et la logique interne de votre script sont corrects.
Si vous utilisez cette commande pour exécuter votre script, Bash vous montrera une sortie de trace lors de l’exécution du script :
bash -x your-script.sh
Bash écrit la sortie de trace dans la fenêtre du terminal. Il affiche chaque commande avec ses arguments, s’il y en a. Cela se produit après que les commandes ont été développées mais avant qu’elles ne soient exécutées.
Cela peut être une aide précieuse pour traquer les bogues insaisissables.