Comment intercepter les erreurs dans les scripts Bash sous Linux

Publié: 2022-08-27
Ordinateur portable Linux affichant une invite bash
fatmawati achmad zaenuri/Shutterstock.com

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.

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.

Personnalisation des erreurs de validation des paramètres dans PowerShell
CONNEXION Personnalisation des erreurs de validation des paramètres dans PowerShell

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

si ( ! mauvaise_commande ); alors
  echo "bad_command a signalé une erreur."
  sortie 1
Fi

Vous devrez rendre le script exécutable avec la commande chmod . 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 mauvaise_commande.sh 

Rendre un script exécutable en utilisant chmod

Lorsque nous exécutons le script, nous voyons le message d'erreur attendu.

 ./bad_command.sh 

Vérification de l'état de sortie d'une commande pour déterminer s'il y a eu une erreur

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 n'est pas nulle. Si la réponse n'est pas zéro (le point d'exclamation est utilisé ici comme opérateur logique NOT ), le corps de l'instruction if est exécuté.

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.

Il peut sembler que la ligne de exit 1 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 l'utilisation de la commande exit 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 l'opérateur logique OR avec l'état de sortie d'une commande et appeler une autre commande ou une fonction dans votre script s'il y a une réponse différente de zéro de la première commande.

 commande_1 || commande_2

Cela fonctionne car soit la première commande s'exécute OR la seconde. 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

gestionnaire_erreur()
{
  echo "Erreur : ($?) $1"
  sortie 1
}

mauvaise_commande || error_handler "mauvaise_commande a échoué, Ligne : ${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 d'exécuter bad_command qui échoue évidemment, donc la commande à droite de l'opérateur logique OR , || , est exécuté. Cela appelle la fonction error_handler et passe une chaîne qui nomme la commande qui a échoué et contient le numéro de ligne de la commande défaillante.

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 $? 

Utilisation de l'opérateur logique OU pour appeler le gestionnaire d'erreurs dans un script

Notre petite fonction error_handler fournit le statut de sortie de la tentative d'exécution de 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 à la commande exit .

Une autre approche serait de développer error_handler pour vérifier les différentes valeurs possibles du statut de sortie et d'effectuer différentes actions en conséquence, en utilisant ce type de construction :

 exit_code=$ ?

if [ $exit_code -eq 1 ]; alors
  echo "Opération non autorisée"

elif [ $exit_code -eq 2 ]; alors
  echo "Mauvaise utilisation des commandes intégrées du shell"
.
.
.
elif [ $status -eq 128 ]; alors
  echo "Argument invalide"
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 la commande set avec l'option -e (erreur). Cela indique au script de se fermer chaque fois qu'une commande échoue ou renvoie un code de sortie supérieur à zéro. De plus, l'utilisation de l'option -E garantit que la détection et l'interception des erreurs fonctionnent dans les fonctions shell.

Comment utiliser set et pipefail dans les scripts Bash sous Linux
CONNEXION Comment utiliser set et pipefail dans les scripts Bash sous Linux

Pour intercepter également les variables non initialisées, ajoutez l'option -u (unset). Pour vous assurer que les erreurs sont détectées dans les séquences canalisées, ajoutez l'option -o pipefail . Sans cela, l'état de sortie d'une séquence canalisée de commandes est l'état de sortie de la commande finale de la séquence. Une commande défaillante au milieu de la séquence canalisée ne serait pas détectée. L'option -o pipefail 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 "Voyons-nous cette ligne?"

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 

Utilisation de la commande set dans un script pour terminer le script si une erreur se produit

La deuxième commande echo 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 capturer 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 '\nTerminé par Ctrl+c'; sortie" SIGINT

compteur=0

alors que c'est vrai
fais 
  echo "Numéro de boucle :" $((++compteur))
  dormir 1
Fini

La commande trap contient une commande echo et la commande exit . Il sera déclenché lorsque SIGINT sera levé. Le reste du script est une simple boucle. Si vous exécutez le script et appuyez sur Ctrl + C, vous verrez le message de la définition du trap et le script se terminera.

 ./sigint.sh 

Utiliser trap dans un script pour intercepter Ctrl+c

Nous pouvons utiliser trap avec le signal ERR 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

piège 'error_handler $ ? $LINENO' ERR

gestionnaire_erreur() {
  echo "Erreur : ($1) s'est produite sur $2"
}

principale() {
  echo "A l'intérieur de la fonction main()"
  mauvaise_commande
  deuxième
  troisième
  quitter $ ?
}

deuxième() {
  echo "Après appel à main()"
  echo "A l'intérieur de la fonction second()"
}

troisième() {
  echo "A l'intérieur de la fonction third()"
}

principale

La majeure partie du script se trouve à l'intérieur de la fonction main , qui appelle les second et third fonctions. Lorsqu'une erreur est rencontrée (dans ce cas, parce que bad_command n'existe pas), l'instruction trap dirige l'erreur vers la fonction error_handler . Il transmet l'état de sortie de la commande ayant échoué et le numéro de ligne à la fonction error_handler .

 ./trap.sh 

Utiliser trap avec ERR pour intercepter les erreurs dans un script

Notre fonction error_handler répertorie simplement les détails de l'erreur dans la fenêtre du terminal. Si vous le souhaitez, vous pouvez ajouter une commande exit à la fonction pour que le script se termine. Ou vous pouvez utiliser une série d'instructions if/elif/fi 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 votre-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.

CONNEXION: Comment valider la syntaxe d'un script Linux Bash avant de l'exécuter