Programmation en Shell Bash sous Linux
But de ce document
Ce document me sert de mémo sur la programmation en Shell Bash. Il liste sans entrer dans le détail les principales possibilités en programmation Bash.
Premier script
Avec votre éditeur de texte préféré, saisir ces deux lignes dans le fichier « test.sh » :
#! /bin/bash
echo "Bonjour le monde"
Remarques :
L’extension du fichier (.sh en l’occurrence) n’a pas d’importance. Il est même possible de ne pas en mettre.
La première ligne est obligatoire car elle permet d’indiquer au shel qui va exécuter le script qu’il doit utiliser le Bash.
Pour faire fonctionner ce script, il faut commencer par le rendre exécutable :
$ chmod +x test.sh
Et nous pouvons le tester :
$ ./test.sh
Bonjour le monde
Les variables
Affecter une valeur à une variable
x=toto
ou en utilisant des guillemets pour protéger les espaces et les caractères spéciaux :
x="toto et tutu"
Remarque : Il ne faut pas mettre d’espace de chaque coté du signe égale
Cette commande permet d’initialiser la variable avec la valeur indiquée seulement si celle-ci est vide :
x=${x:-valeur par défaut}
Récupérer le résultat d’une commande
x=$(ls /etc)
ou :
x=`ls /etc`
Afficher le contenu d’une variable
echo $x
ou :
echo ${x}
Les tableaux
Affecter une valeur à un tableau :
$ tab[0]=toto
Lire le contenu du tableau
$ echo ${tab[0]}
Remarque : Dans ce cas, il est obligatoire d’utiliser les accolades pour lire le contenu
Protection des expressions
Le « backslash » permet de protéger tous les caractères spéciaux y compris lui même :
echo \* \# \$ \' \" \\
* # $ ' " \
Le « guillemet double » permet de protéger tous les caractères sauf lui même qu’il faut protéger avec un « backslash » et le « $ » ce qui permet d’interpréter le contenu des variables :
$ echo "* # $ \ ' \" x=$x"
* # $ \ ' " x=toto
L’apostrophe permet de protéger tous les caractères sauf elle même :
$ echo '* # $ \ " x=$x'
* # $ \ " x=$x
Les calculs
Addition :
$ a=10; b=20; c=$((a+b)); echo "a+b=$c"
a+b=30
Multiplication et division :
$ a=10; b=20; c=2; d=$((a*b/c)); echo "a*b/c=$d"
a*b/c=100
Le traitement des chaînes de caractères
Concaténation de chaînes de caractères :
$ a=toto; b=tutu; c="$a et $b"; echo $c
toto et tutu
Supprime les 5 premiers caractères de la chaîne :
$ fich="test.tar.gz" ; echo ${fich:5}
tar.gz
Extrait 3 caractères à partir du cinquième :
tony@etch:~$ fich="test.tar.gz" ; echo ${fich:5:3}
tar
Le signe « % » permet de supprimer le plus petit suffixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich%.*}
test.tar
Le signe « %% » permet de supprimer le plus grand suffixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich%%.*}
test
Le signe « # » permet de supprimer le plus petit préfixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich#*.}
tar.gz
Le signe « ## » permet de supprimer le plus grand préfixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich##*.}
gz
Remplace la première sous-chaîne trouvée par celle proposée :
fich="test.tar.gz" ; echo ${fich/.tar.gz/.tgz}
test.tgz
Remplace toutes les sous-chaînes trouvées par celle proposée :
fich="test.tar.gz.tar.gz" ; echo ${fich//.tar.gz/.tgz}
test.tgz.tgz
La commande suivante permet de retrouver la longueur d’une chaîne :
$ fich="test.tar.gz" ; echo ${#fich}
11
Utilisation des pipelines
Le caractère « | » permet d’envoyer la sortie d’une commande sur l’entrée de la commande suivante. Exemple :
$ df -h | tail -1 | sed "s/ */ /g" | cut -d " " -f 4
4,2G
La même chose avec « awk » :
$ df -h | tail -1 | awk '{print $4}'
4,2G
L’enchaînement de commandes sur une même ligne
Ces commandes sont exécutées les unes derrières les autres :
$ echo debut; echo fin
debut
fin
La dernière commande est exécuté uniquement si la commande précédente c’est exécutée avec succès :
$ echo debut; true && echo fin
debut
fin
La dernière commande est exécuté uniquement si la commande précédente a retourné une erreur :
$ echo debut; false || echo fin
debut
fin
Les redirections
Envoie la sortie standard dans le fichier ls.txt :
$ ls /etc/ >ls.txt
Envoie la sortie standard à la fin du fichier ls.txt :
$ ls /etc/ >>ls.txt
Envoie la sortie d’erreur dans le fichier ls.err :
$ ls /toto 2>ls.err
Redirection de la sortie standard et de la sortie d’erreur dans deux fichiers séparés :
$ ls /etc/ >ls.txt 2>ls.err
Envoie la sortie d’erreur et la sortie standard dans le fichier ls.txt :
$ ls /toto 2>&1 >ls.txt
La même chose en plus court :
$ ls /toto &>ls.txt
Redirige le résultat de deux commandes dans ls.txt
(ls /etc; ls /toto) &>ls.txt
Opérateur de test [ ]
L’opérateur de test « [ ] » retourne « vrai » si la condition est vrai et « faux » dans le cas contraire. Donc cette ligne exécutera la commande « echo » seulement si le fichier existe :
$ [ -f ./test.sh ] && echo "OK"
Arguments les plus courant de l’opérateur
Option | Vrai si |
-e fichier | Le fichier indiqué existe |
-d répertoire | Le répertoire indiqué existe |
-f fichier | Le fichier indiqué est un fichier régulier |
-h fichier | Le fichier indiqué est un lien symbolique |
chaine1 = chaine2 | Les deux chaînes sont identiques |
val1 -eq val2 | Les deux valeurs sont égales |
val1 -ge val2 | val1 >= val2 |
val1 -gt val2 | val1 > val2 |
val1 -le val2 | val1 <= val2 |
val1 -lt val2 | val1 < val2 |
val1 -ne val2 | val1 != val2 |
Condition (if...else...fi)
Syntaxe générale :
if condition ; then
...
else
...
fi
Cette instruction s’utilise en générale avec l’opérateur de test détaillé au chapitre précédent. Exemple :
if [ -f ./test.sh ] ; then
echo "OK"
fi
Ou sur une seule ligne :
if [ -f ./test.sh ] ; then echo "OK" ; fi
Condition « case...esac »
Syntaxe générale :
case expression in
motif1) commande 1 ;;
motif2) commande 2 ;;
...
esac
Le motif peut contenir
* : N’importe quelle chaîne de caractères
? : N’importe quel caractère
[abc] : Alternance de caractères
[A-Z] : Suite de caractères
| : OU permettant de combiner plusieurs motifs
Exemple :
#! /bin/bash
while [ -n "$1" ]; do
ping -c 1 -w 1 $1 >/dev/null 2>&1
case $? in
0) echo -e "$1 \t OK !";;
1) echo -e "$1 \t injoignable !";;
2) echo -e "$1 \t inexistant !";;
esac
shift
done
Boucle « while...done »
Syntaxe générale :
while condition ; do
...
done
Exemple :
i=0 ;
while [ $i -lt 5 ] ; do
i=$((i+1))
echo $i
done
La même chose sur une ligne :
i=0 ; while [ $i -lt 5 ] ; do i=$((i+1)) ; echo $i ; done
Un autre exemple en utilisant l’instruction « break »permettant de sortie de la boucle :
i=0
while true ; do
echo "$i avec break"
i=$((i+1))
[ $i -eq 5 ] && break
done
Boucle « until...done »
Syntaxe générale :
until condition ; do
...
done
Boucle « for...done »
Le fonctionnement de cette boucle est très différent de celui des autres langages.
Syntaxe :
for variale in liste_de_mots ; do
...
done
Exemple :
$ for var in a b c d ; do echo $var ; done
Renommer une série de fichiers :
for i in *.tgz ; do mv $i ${i%tgz}tar.gz ; done
Boucle « select...done » permet de réaliser des listes de choix
Exemple :
$ select var in a b c ; do echo $var ; done
1) a
2) b
3) c
#?
Fonctions
Voici la syntaxe générale d’une fonction :
function nom_de_la_fonction ()
{
...
}
Passage d’arguments
$0 : Contient le nom du script
$1 : Premier argument ($2 : Deuxième argument,..)
$10 : Dixième argument (Attention : $10 retourne le premier argument suivi de 0
$* : Tous les arguments mais sans protéger les espaces et caractères spéciaux
"$@" : Tous les arguments mais en protégeant les espaces et caractères spéciaux
$# : Nombre d’arguments de la fonction
La commande « shift » permet de décaler les variables (Le contenu de $1 est remplacé par celui de $2,..). Cela permet par exemple de lire le contenu de toute les variables :
while [ -n "$1" ] ; do
echo $1
shift
done
Affiche la lites des arguments passés au script :
for i in "$@" ; do
echo $i
done
La même chose en plus court :
for i ; do
echo $i
done
Traitement des options dans un script
Traitement des options sans arguments
L’instruction « getopts » permet de traiter les options passées en ligne de commande. Dans cet exemple, nous avons comme options « -a, -b et/ou -c ». L’ordre des options n’a pas d’importance et il est possible de les coller ou pas.
while getopts "abc" option ; do
case $option in
a) echo "Option a";;
b) echo "Option b";;
c) echo "Option c";;
esac
done
Test :
$ ./traite_arguments.sh -c -ab
Option c
Option a
Option b
Traitement des options avec argument
Si une option nécessite un argument, il faut la faire suivre du signe « : » et la valeur de l’argument sera accessible dans la variable « OPTARG ». Exemple :
while getopts "abc:d:" option ; do
case $option in
a) echo "Option a";;
b) echo "Option b";;
c) echo "Option c, argument $OPTARG";;
d) echo "Option d, argument $OPTARG";;
esac
done
Test :
$ ./traite_arguments2.sh -c toto -ab -d tutu
Option c, argument toto
Option a
Option b
Option d, argument tutu
Traitement des erreurs
Pour gérer les erreurs, il faut ajouter « : » dans la liste des options possibles. Cela permettra de traiter les options sans arguments. Et pour traiter les options inconnues « getopts » retourne « ? » qu’il suffit de traiter dans le script :
while getopts ":abc:d:" option ; do
case $option in
a) echo "Option a";;
b) echo "Option b";;
c) echo "Option c, argument $OPTARG";;
d) echo "Option d, argument $OPTARG";;
:) echo "Argument manquant pour l'option -$OPTARG";;
?) echo "Option -$OPTARG inconnue";;
esac
done
Traitement des options longues sans arguments
Par défaut « getopts » ne sais pas traiter les options longues mais une petite astuce permet de contourner ce problème pour les options sans argument. Pour cela il suffit de d’ajouter dans les options « - » et de traiter en premier le cas des options longues.
while getopts ":hv-:" option ; do
if [ "$option" = "-" ] ; then
case $OPTARG in
help) option=h;;
version) option=v;;
*) echo "Option $OPTARG inconnue";;
esac
fi
case $option in
h) echo "Option h";;
v) echo "Option v";;
?) echo "Option -$OPTARG inconnue";;
esac
done
Test :
$ ./traite_arguments3.sh --version -h -a
Option v
Option h
Option -a inconnue
Pour avoir plus d’informations
Pour avoir plus d’explications sur la programmation en Bash mais également avec Sed, Awk, Perl, Tcl, Tk, Python, Ruby ..., je vous conseille la lecture de cet excellent livre dont deux chapitres sont disponibles au format PDF :
http://www.editions-eyrolles.com/Livre/9782212110289/langages-de-scripts-sous-linux
Historique des modifications
Version | Date | Commentaire |
---|---|---|
0.1 | 14/08/08 | Création par Tony GALMICHE |