3.3 Leçon 2
Certification : |
Linux Essentials |
---|---|
Version : |
1.6 |
Thème : |
3 La Puissance de la Ligne de Commande |
Objectif : |
3.3 Transformer les Commandes en Script |
Leçon : |
2 sur 2 |
Introduction
Dans la dernière section, nous avons utilisé cet exemple simple pour démontrer l’écriture de script Bash :
#!/bin/bash # Un script simple pour saluer un seul utilisateur. if [ $# -eq 1 ] then username=$1 echo "Hello $username!" else echo "Veuillez ne saisir qu'un seul argument." fi echo "Nombre d'arguments : $#."
-
Tous les scripts doivent commencer par un shebang, qui définit le chemin vers l’interprète.
-
Tous les scripts doivent comporter des commentaires pour décrire leur utilisation.
-
Ce script particulier fonctionne avec un argument, qui est transmis au script lorsqu’il est appelé.
-
Ce script contient une déclaration if, qui teste les conditions d’une variable intégrée
$#
. Cette variable contient le nombre d’arguments. -
Si le nombre d’arguments passés au script est égal à 1, alors la valeur du premier argument est passée à une nouvelle variable appelée
username
et le script envoie un message d’accueil à l’utilisateur. Sinon, un message d’erreur est affiché. -
Enfin, le script affiche le nombre d’arguments. Ceci est utile pour le débogage.
Ceci est un exemple utile pour commencer à expliquer certaines des autres caractéristiques des Scripts Bash.
Codes de Sortie
Vous remarquerez que notre script présente deux résultats possibles : soit il affiche "Hello <user>!"
, soit il affiche un message d’erreur. C’est tout à fait normal pour beaucoup de nos utilitaires de base. Prenons l’exemple de cat
, que vous commencez sans doute à connaître.
Comparons une utilisation réussie de cat
avec une situation où elle échoue. Nous vous rappelons que notre exemple ci-dessus est un script appelé new_script.sh
.
$ cat -n new_script.sh 1 #!/bin/bash 2 3 # Un script simple pour saluer un seul utilisateur. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 else 11 echo "Veuillez ne saisir qu'un seul argument." 12 fi 13 echo "Nombre d'arguments : $#."
Cette commande réussit, et vous remarquerez que l’option -n
a également affiché des numéros de ligne. Ceux-ci sont très utiles pour déboguer les scripts, mais veuillez noter qu’ils ne font pas partie du script.
Nous allons maintenant vérifier la valeur d’une nouvelle variable intégrée $?
Pour l’instant, il suffit de noter la sortie :
$ echo $? 0
Considérons maintenant une situation où cat
échouera. Nous allons d’abord voir un message d’erreur, puis vérifier la valeur de $?
.
$ cat -n dummyfile.sh cat: dummyfile.sh: No such file or directory $ echo $? 1
L’explication de ce comportement est la suivante : toute exécution de l’utilitaire cat
renvoie un code de sortie. Un code de sortie nous indiquera si la commande a réussi ou si elle a subi une erreur. Un code de sortie égal à zéro indique que la commande a réussi. Cela est vrai pour presque toutes les commandes Linux avec lesquelles vous travaillerez. Tout autre code de sortie indiquera une erreur quelconque. Le code de sortie de la dernière commande exécutée sera stocké dans la variable $?
.
Les codes de sortie ne sont généralement pas vus par les utilisateurs humains, mais ils sont très utiles lors de l’écriture de scripts. Prenons l’exemple d’un script dans lequel nous pouvons copier des fichiers sur un lecteur réseau distant. La tâche de copie peut échouer de plusieurs façons : par exemple, notre machine locale peut ne pas être connectée au réseau, ou le disque distant peut être plein. En vérifiant le code de sortie de notre utilitaire de copie, nous pouvons signaler à l’utilisateur les problèmes rencontrés lors de l’exécution du script.
La mise en œuvre de codes de sortie est une très bonne pratique, c’est pourquoi nous allons le faire maintenant. Nous avons deux résultats possibles pour notre script, un succès ou un échec. Utilisons le zéro pour indiquer un succès et le un pour indiquer un échec.
1 #!/bin/bash 2 3 # Un script simple pour saluer un seul utilisateur. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 exit 0 11 else 12 echo "Veuillez ne saisir qu'un seul argument." 13 exit 1 14 fi 15 echo "Nombre d'arguments : $#."
$ ./new_script.sh Carol Hello Carol! $ echo $? 0
Remarquez que la commande echo
sur la ligne 15 a été entièrement ignorée. L’utilisation de exit
terminera le script immédiatement, donc cette ligne n’est jamais rencontrée.
Gérer Plusieurs Arguments
Jusqu’à présent, notre script ne peut gérer qu’un seul nom d’utilisateur à la fois. Un nombre d’arguments supérieur à un entraînera une erreur. Voyons comment nous pouvons rendre ce script plus polyvalent.
Le premier réflexe d’un utilisateur pourrait être d’utiliser plus de variables positionnelles telles que $2
, $3
, etc. Malheureusement, nous ne pouvons pas anticiper le nombre d’arguments qu’un utilisateur pourrait choisir d’utiliser. Pour résoudre ce problème, il sera utile d’introduire davantage de variables intégrées.
Nous allons modifier la logique de notre script. Le fait d’avoir zéro argument devrait entraîner une erreur, mais tout autre nombre d’arguments devrait réussir. Ce nouveau script sera appelé friendly2.sh
.
1 #!/bin/bash 2 3 # un script convivial pour saluer les utilisateurs 4 5 if [ $# -eq 0 ] 6 then 7 echo "Veuillez entrer au moins un utilisateur à saluer." 8 exit 1 9 else 10 echo "Hello $@!" 11 exit 0 12 fi
$ ./friendly2.sh Carol Dave Henry Hello Carol Dave Henry!
Il y a deux variables intégrées qui contiennent tous les arguments passés au script : $@
et $*
. La plupart du temps, les deux se comportent de la même manière. Bash va analyser les arguments et séparer chaque argument lorsqu’il rencontre un espace entre eux. En fait, le contenu de $@
ressemble à ceci :
|
|
|
|
|
|
Si vous êtes familier avec d’autres langages de programmation, vous pouvez reconnaître ce type de variable comme un tableau. Les tableaux en Bash peuvent être créés simplement en mettant de l’espace entre des éléments comme la variable FILES
dans le script arraytest
ci-dessous :
FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot"
Il contient une liste de nombreux éléments. Jusqu’à présent, cela n’est pas très utile, car nous n’avons pas encore introduit de moyen de traiter ces éléments individuellement.
Les Boucles For
Référons-nous à l’exemple arraytest
présenté précédemment. Si vous vous souvenez bien, dans cet exemple, nous spécifions un tableau appelé FILES
. Ce dont nous avons besoin, c’est d’un moyen de "déballer" cette variable et d’accéder à chaque valeur individuelle, l’une après l’autre. Pour ce faire, nous utiliserons une structure appelée boucle for, qui est présente dans tous les langages de programmation. Nous nous référerons à deux variables : l’une est la plage et l’autre est la valeur individuelle sur laquelle nous travaillons actuellement. Ceci est le script dans son intégralité :
#!/bin/bash FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot" for file in $FILES do ls -lh $file done
$ ./arraytest lrwxrwxrwx 1 root root 10 Apr 24 11:02 /usr/sbin/accept -> cupsaccept -rwxr-xr-x 1 root root 54K Mar 22 14:32 /usr/sbin/pwck -rwxr-xr-x 1 root root 43K Jan 14 07:17 /usr/sbin/chroot
Si vous vous référez à nouveau à l’exemple friendly2.sh
ci-dessus, vous pouvez voir que nous travaillons avec un ensemble de valeurs contenues dans une seule variable $@
. Par souci de clarté, nous appellerons cette dernière variable username
. Notre script ressemble maintenant à ceci :
1 #!/bin/bash 2 3 # un script convivial pour saluer les utilisateurs 4 5 if [ $# -eq 0 ] 6 then 7 echo "Veuillez entrer au moins un utilisateur à saluer." 8 exit 1 9 else 10 for username in $@ 11 do 12 echo "Hello $username!" 13 done 14 exit 0 15 fi
Rappelez-vous que la variable que vous définissez ici peut être nommée comme vous le souhaitez, et que toutes les lignes à l’intérieur de do… done
s’exécuteront une fois pour chaque élément du tableau. Observons la sortie de notre script :
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry!
Supposons maintenant que nous voulions donner à notre sortie un aspect un peu plus humain. Nous voulons que notre salutation soit sur une seule ligne.
1 #!/bin/bash 2 3 # un script convivial pour saluer les utilisateurs 4 5 if [ $# -eq 0 ] 6 then 7 echo "Veuillez entrer au moins un utilisateur à saluer." 8 exit 1 9 else 10 echo -n "Hello $1" 11 shift 12 for username in $@ 13 do 14 echo -n ", et $username" 15 done 16 echo "!" 17 exit 0 18 fi
Quelques notes :
-
L’utilisation de
-n
avececho
supprimera le saut de ligne après l’affichage. Cela signifie que tous les echos seront affichés sur la même ligne, et que le saut de ligne ne sera affiché qu’après le!
de la ligne 16. -
La commande
shift
supprimera le premier élément de notre tableau, afin que ceci :
|
|
|
|
|
|
Devient ceci :
|
|
|
|
Observons le résultat :
$ ./friendly2.sh Carol Hello Carol! $ ./friendly2.sh Carol Dave Henry Hello Carol, et Dave, et Henry!
Usage d’Expressions Régulières pour Vérifier des Erreurs
Il est possible que nous voulions vérifier tous les arguments que l’utilisateur saisit. Par exemple, nous voulons peut-être nous assurer que tous les noms transmis à friendly2.sh
ne contiennent que des lettres, et que tout caractère spécial ou chiffre provoquera une erreur. Pour effectuer cette vérification d’erreur, nous utiliserons grep
.
Rappelons que nous pouvons utiliser des expressions régulières avec grep
.
$ echo Animal | grep "^[A-Za-z]*$" Animal $ echo $? 0
$ echo 4n1ml | grep "^[A-Za-z]*$" $ echo $? 1
Le ^
et le $
indiquent respectivement le début et la fin de la ligne. Le [A-Za-z]
indique une série de lettres, en majuscules ou en minuscules. Le *
est un quantificateur et modifie notre plage de lettres de manière que nous fassions correspondre de zéro à plusieurs lettres. En résumé, notre grep
réussira si la saisie ne comporte que des lettres, et échouera dans le cas contraire.
Ensuite, il faut noter que grep
renvoie des codes de sortie en fonction de l’existence ou non d’une correspondance. Une correspondance positive renvoie 0
, et une absence de correspondance renvoie un 1
. Nous pouvons utiliser cela pour tester nos arguments à l’intérieur de notre script.
1 #!/bin/bash 2 3 # un script convivial pour saluer les utilisateurs 4 5 if [ $# -eq 0 ] 6 then 7 echo "Veuillez entrer au moins un utilisateur à saluer." 8 exit 1 9 else 10 for username in $@ 11 do 12 echo $username | grep "^[A-Za-z]*$" > /dev/null 13 if [ $? -eq 1 ] 14 then 15 echo "ERREUR : Les noms ne doivent contenir que des lettres." 16 exit 2 17 else 18 echo "Hello $username!" 19 fi 20 done 21 exit 0 22 fi
Sur la ligne 12, nous redirigeons la sortie standard vers /dev/null
, ce qui est une façon simple de la supprimer. Nous ne voulons pas voir de sortie de la commande grep
, nous voulons seulement tester son code de sortie, ce qui se passe sur la ligne 13. Notez également que nous utilisons un code de sortie de 2
pour indiquer un argument non valide. Il est généralement bon d’utiliser différents codes de sortie pour indiquer différentes erreurs ; de cette façon, un utilisateur averti peut utiliser ces codes de sortie pour dépanner.
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry! $ ./friendly2.sh 42 Carol Dave Henry ERREUR : Les noms ne doivent contenir que des lettres. $ echo $? 2
Exercices Guidés
-
Lisez le contenu de
script1.sh
ci-dessous :#!/bin/bash if [ $# -lt 1 ] then echo "Ce script nécessite au moins 1 argument." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "pas de gateau pour toi !" exit 2 fi echo "voici ton gateau !" exit 0
Quel est le résultat de ces commandes ?
-
./script1.sh
-
echo $?
-
./script1.sh cake
-
echo $?
-
./script1.sh CAKE
-
echo $?
-
-
Lisez le contenu du fichier
script2.sh
:for filename in $1/*.txt do cp $filename $filename.bak done
Décrivez le but de ce script tel que vous le comprenez.
Exercices d’Exploration
-
Créez un script qui prendra un nombre quelconque d’arguments de l’utilisateur et n’affichera que les arguments qui sont des nombres supérieurs à 10.
Résumé
Dans cette section, vous avez appris :
-
Quels sont les codes de sortie, leur signification et comment les mettre en œuvre
-
Comment vérifier le code de sortie d’une commande
-
Ce que sont les boucles
for
et comment les utiliser avec des tableaux -
Comment utiliser
grep
, les expressions régulières et les codes de sortie pour vérifier les entrées de l’utilisateur dans les scripts.
Commandes utilisées dans les exercices :
shift
-
Ceci supprimera le premier élément d’un tableau.
Variables spéciales :
$?
-
Contient le code de sortie de la dernière commande exécutée.
$@
,$*
-
Contient tous les arguments passés au script, sous forme de tableau.
Réponses aux Exercices Guidés
-
Lisez le contenu de
script1.sh
ci-dessous :#!/bin/bash if [ $# -lt 1 ] then echo "Ce script nécessite au moins 1 argument." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "pas de gateau pour toi !" exit 2 fi echo "voici ton gateau !" exit 0
Quel est le résultat de ces commandes ?
-
Commande :
./script1.sh
Sortie :
Ce script nécessite au moins 1 argument.
-
Commande :
echo $?
Sortie :
1
-
Commande :
./script1.sh gateau
Sortie :
pas de gateau pour toi !
-
Commande :
echo $?
Sortie :
2
-
Commande :
./script1.sh GATEAU
Sortie :
voici ton gateau !
-
Commande :
echo $?
Sortie :
0
-
-
Lisez le contenu du fichier
script2.sh
:for filename in $1/*.txt do cp $filename $filename.bak done
Décrivez le but de ce script tel que vous le comprenez.
Ce script fera des copies de sauvegarde de tous les fichiers se terminant par
.txt
dans un sous-répertoire défini dans le premier argument.
Réponses aux Exercices d’Exploration
-
Créez un script qui prendra un nombre quelconque d’arguments de l’utilisateur et n’affichera que les arguments qui sont des nombres supérieurs à 10.
#!/bin/bash for i in $@ do echo $i | grep "^[0-9]*$" > /dev/null if [ $? -eq 0 ] then if [ $i -gt 10 ] then echo -n "$i " fi fi done echo ""