Comment utiliser set et pipefail dans les scripts Bash sous Linux
Agence web » Actualités du digital » Comment utiliser set et pipefail dans les scripts Bash sous Linux

Comment utiliser set et pipefail dans les scripts Bash sous Linux

Le Linux set et pipefail Les commandes dictent ce qui se passe lorsqu’un échec se produit dans un script Bash. Il y a plus à penser que cela devrait-il s’arrêter ou devrait-il continuer.

EN RELATION: Le guide du débutant pour les scripts shell : les bases

Scripts bash et conditions d’erreur

Les scripts shell bash sont excellents. Ils sont rapides à écrire et n’ont pas besoin d’être compilés. Toute action répétitive ou en plusieurs étapes que vous devez effectuer peut être intégrée dans un script pratique. Et comme les scripts peuvent appeler n’importe quel utilitaire Linux standard, vous n’êtes pas limité aux capacités du langage shell lui-même.

Mais des problèmes peuvent survenir lorsque vous appelez un utilitaire ou un programme externe. S’il échoue, l’utilitaire externe se fermera et enverra un code de retour au shell, et il pourrait même imprimer un message d’erreur au terminal. Mais votre script continuera à être traité. Ce n’est peut-être pas ce que vous vouliez. Si une erreur se produit au début de l’exécution du script, cela peut aggraver les problèmes si le reste du script est autorisé à s’exécuter.

Vous pouvez vérifier le code de retour de chaque processus externe à mesure qu’il se termine, mais cela devient difficile lorsque les processus sont redirigés vers d’autres processus. Le code de retour proviendra du processus à la fin du tube, et non de celui du milieu qui a échoué. Bien sûr, des erreurs peuvent également se produire à l’intérieur de votre script, comme essayer d’accéder à une variable non initialisée.

le set et pipefile Les commandes vous permettent de décider ce qui se passe lorsque des erreurs comme celles-ci se produisent. Ils vous permettent également de détecter les erreurs même lorsqu’elles se produisent au milieu d’une chaîne de tuyaux.

Voici comment les utiliser.

Démonstration du problème

Voici un script Bash trivial. Il renvoie deux lignes de texte au terminal. Vous pouvez exécuter ce script si vous copiez le texte dans un éditeur et l’enregistrez sous « script-1.sh ».

#!/bin/bash

echo This will happen first 
echo This will happen second

Pour le rendre exécutable, vous devrez utiliser chmod:

chmod +x script-1.sh

Vous devrez exécuter cette commande sur chaque script si vous souhaitez les exécuter sur votre ordinateur. Exécutons le script :

./script-1.sh

Exécution d'un script simple sans erreur.

Les deux lignes de texte sont envoyées à la fenêtre du terminal comme prévu.

Modifions légèrement le script. Nous demanderons ls pour lister les détails d’un fichier qui n’existe pas. Cela échouera. Nous l’avons enregistré sous le nom de « script-2.sh » et l’avons rendu exécutable.

#!/bin/bash

echo This will happen first
ls imaginary-filename
echo This will happen second

Lorsque nous exécutons ce script, nous voyons le message d’erreur de ls .

./script-2.sh

Exécution d'un script et génération d'une condition d'échec.

Bien que le ls La commande a échoué, le script a continué à s’exécuter. Et même s’il y a eu une erreur lors de l’exécution du script, le code de retour du script au shell est zéro, ce qui indique un succès. Nous pouvons vérifier cela en utilisant echo et le $? variable qui contient le dernier code de retour envoyé au shell.

echo $?

Vérification du code retour du dernier script exécuté.

Le zéro qui est signalé est le code de retour du deuxième écho du script. Il y a donc deux problèmes avec ce scénario. Le premier est que le script a eu une erreur mais qu’il a continué à s’exécuter. Cela peut entraîner d’autres problèmes si le reste du script attend ou dépend de l’action qui a échoué et qui a effectivement réussi. Et la seconde est que si un autre script ou processus a besoin de vérifier le succès ou l’échec de ce script, il obtiendra une fausse lecture.

L’option set -e

le set -e (exit) provoque la sortie d’un script si l’un des processus qu’il appelle génère un code retour différent de zéro. Tout ce qui n’est pas nul est considéré comme un échec.

En ajoutant le set -e option au début du script, nous pouvons changer son comportement. Il s’agit de « script-3.sh ».

#!/bin/bash 
set -e

echo This will happen first
ls imaginary-filename
echo This will happen second

Si nous exécutons ce script, nous verrons l’effet de set -e.

./script-3.sh
echo $?

Terminer un script en cas d'erreur et définir correctement le code de retour.

Le script est arrêté et le code de retour envoyé au shell est une valeur non nulle.

Faire face aux défaillances dans les tuyaux

La tuyauterie ajoute plus de complexité au problème. Le code de retour qui sort d’une séquence de commandes canalisée est le code de retour de la dernière commande de la chaîne. S’il y a un échec avec une commande au milieu de la chaîne, nous revenons à la case départ. Ce code de retour est perdu et le script poursuivra le traitement.

Nous pouvons voir les effets des commandes de tuyauterie avec différents codes de retour en utilisant le true et false intégrés au shell. Ces deux commandes ne font que générer un code de retour de zéro ou un, respectivement.

true
echo $?
false
echo $?

Les commandes intégrées true et false du shell bash.

Si on pipe false dans true -avec false représentant un processus défaillant – nous obtenons truele code de retour de zéro.

false | true
echo $?

Passer du faux au vrai.

Bash a une variable tableau appelée PIPESTATUSet cela capture tous les codes de retour de chaque programme de la chaîne de canaux.

false | true | false | true
echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}"

Utilisation de PIPESTATUS pour voir le code de retour de tous les programmes d'une chaîne de tubes.

PIPESTATUS ne contient que les codes de retour jusqu’à ce que le programme suivant s’exécute, et essayer de déterminer quel code de retour va avec quel programme peut devenir très désordonné très rapidement.

C’est ici que set -o (choix) et pipefail Entrez. C’est « script-4.sh ». Cela essaiera de canaliser le contenu d’un fichier qui n’existe pas dans wc.

#!/bin/bash 
set -e

echo This will happen first
cat script-99.sh | wc -l
echo This will happen second

Cela échoue, comme on pouvait s’y attendre.

./script-4.sh
echo $?

Exécution d'un script avec une erreur dans une chaîne de canaux.

Le premier zéro est la sortie de wc, nous indiquant qu’il n’a lu aucune ligne pour le fichier manquant. Le deuxième zéro est le code de retour du deuxième echo commander.

Nous ajouterons dans le -o pipefail enregistrez-le sous « script-5.sh » et rendez-le exécutable.

#!/bin/bash 
set -eo pipefail

echo This will happen first
cat script-99.sh | wc -l
echo This will happen second

Exécutons cela et vérifions le code de retour.

./script-5.sh
echo $?

Exécution d'un script qui intercepte les erreurs dans les chaînes de canaux et définit correctement le code de retour.

Le script s’arrête et la seconde echo la commande n’est pas exécutée. Le code de retour envoyé au shell est un, indiquant correctement un échec.

EN RELATION: Comment utiliser la commande Echo sous Linux

Attraper des variables non initialisées

Les variables non initialisées peuvent être difficiles à repérer dans un script réel. Si nous essayons de echo la valeur d’une variable non initialisée, echo imprime simplement une ligne vierge. Il ne génère pas de message d’erreur. Le reste du script continuera à s’exécuter.

Il s’agit de script-6.sh.

#!/bin/bash 
set -eo pipefail

echo "$notset" 
echo "Another echo command"

Nous allons l’exécuter et observer son comportement.

./script-6.sh
echo $?

Exécution d'un script qui ne capture pas les variables non initialisées.

Le script parcourt la variable non initialisée et continue de s’exécuter. Le code de retour est zéro. Essayer de trouver une erreur comme celle-ci dans un script très long et compliqué peut être très difficile.

Nous pouvons piéger ce type d’erreur en utilisant le set -u (non défini). Nous allons l’ajouter à notre collection croissante d’options set en haut du script, l’enregistrer sous « script-7.sh » et le rendre exécutable.

#!/bin/bash 

set -eou pipefail

echo "$notset" 

echo "Another echo command"

Exécutons le script :

./script-7.sh
echo $?

Exécution d'un script qui capture des variables non initialisées.

La variable non initialisée est détectée, le script s’arrête et le code de retour est défini sur un.

le -u (non défini) l’option est suffisamment intelligente ne pas être déclenché par des situations où vous pouvez légitimement interagir avec une variable non initialisée.

Dans « script-8.sh », le script vérifie si la variable New_Var est initialisé ou non. Vous ne voulez pas que le script s’arrête ici, dans un script du monde réel, vous effectuerez un traitement supplémentaire et gérerez la situation vous-même.

Notez que nous avons ajouté le -u option comme le seconde option dans l’instruction set. le -o pipefail l’option doit venir en dernier.

#!/bin/bash 

set -euo pipefail

if [ -z "${New_Var:-}" ]; then 

echo "New_Var has no value assigned to it." 

fi

Dans « script-9.sh », la variable non initialisée est testée et si elle n’est pas initialisée, une valeur par défaut est fournie à la place.

#!/bin/bash
set -euo pipefail

default_value=484
Value=${New_Var:-$default_value}
echo "New_Var=$Value"

Les scripts sont autorisés à s’exécuter jusqu’à leur achèvement.

./script-8.sh
./script-9.sh

Exécution de deux scripts où les variables non initialisées sont gérées en interne et l'option -u ne se déclenche pas.

Scellé à la hache

Une autre option pratique à utiliser est la set -x (exécuter et imprimer). Lorsque vous écrivez des scripts, cela peut vous sauver la vie. il imprime les commandes et leurs paramètres au fur et à mesure de leur exécution.

Il vous donne une forme de trace d’exécution rapide et prête à l’emploi. Isoler les failles logiques et repérer les bogues devient beaucoup, beaucoup plus facile.

Nous allons ajouter l’option set -x à « script-8.sh », l’enregistrer sous « script-10.sh » et le rendre exécutable.

#!/bin/bash
set -euxo pipefail

if [ -z "${New_Var:-}" ]; then
  echo "New_Var has no value assigned to it."
fi

Exécutez-le pour voir les lignes de trace.

./script-10.sh

Exécution d'un script avec -x lignes de trace écrites sur le terminal.

Repérer les bogues dans ces exemples de scripts triviaux est facile. Lorsque vous commencerez à écrire des scripts plus complexes, ces options feront leurs preuves.

★★★★★