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 mondeLes 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=totoL’apostrophe permet de protéger tous les caractères sauf elle même :
$ echo '* # $ \ " x=$x'
* # $ \ " x=$xLes calculs
Addition :
$ a=10; b=20; c=$((a+b)); echo "a+b=$c"
a+b=30Multiplication et division :
$ a=10; b=20; c=2; d=$((a*b/c)); echo "a*b/c=$d"
a*b/c=100Le 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 tutuSupprime les 5 premiers caractères de la chaîne :
$ fich="test.tar.gz" ; echo ${fich:5}
tar.gzExtrait 3 caractères à partir du cinquième :
tony@etch:~$ fich="test.tar.gz" ; echo ${fich:5:3}
tarLe signe « % » permet de supprimer le plus petit suffixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich%.*}
test.tarLe signe « %% » permet de supprimer le plus grand suffixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich%%.*}
testLe signe « # » permet de supprimer le plus petit préfixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich#*.}
tar.gzLe signe « ## » permet de supprimer le plus grand préfixe correspond à l’expression régulière :
$ fich="test.tar.gz" ; echo ${fich##*.}
gzRemplace la première sous-chaîne trouvée par celle proposée :
fich="test.tar.gz" ; echo ${fich/.tar.gz/.tgz}
test.tgzRemplace toutes les sous-chaînes trouvées par celle proposée :
fich="test.tar.gz.tar.gz" ; echo ${fich//.tar.gz/.tgz}
test.tgz.tgzLa commande suivante permet de retrouver la longueur d’une chaîne :
$ fich="test.tar.gz" ; echo ${#fich}
11Utilisation 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,2GLa même chose avec « awk » :
$ df -h | tail -1 | awk '{print $4}'
4,2GL’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
finLa 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
finLa dernière commande est exécuté uniquement si la commande précédente a retourné une erreur :
$ echo debut; false || echo fin
debut
finLes 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
...
fiCette 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"
fiOu 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
...
doneExemple :
i=0 ;
while [ $i -lt 5 ] ; do
i=$((i+1))
echo $i
doneLa 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
doneBoucle « until...done »
Syntaxe générale :
until condition ; do
...
doneBoucle « 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
...
doneExemple :
$ 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
doneAffiche la lites des arguments passés au script :
for i in "$@" ; do
echo $i
doneLa même chose en plus court :
for i ; do
echo $i
doneTraitement 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
doneTest :
$ ./traite_arguments.sh -c -ab
Option c
Option a
Option bTraitement 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
doneTest :
$ ./traite_arguments2.sh -c toto -ab -d tutu
Option c, argument toto
Option a
Option b
Option d, argument tutuTraitement 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
doneTraitement 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
doneTest :
$ ./traite_arguments3.sh --version -h -a
Option v
Option h
Option -a inconnuePour 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 |
