Skip to Content

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
  • Commentaires

    Programmation en Shell Bash sous Linux

    Bonjour,

    quelques astuces pour compléter ton mémo :

    Comment cacher la saisie d’entrée clavier (utile pour les mots de passe)
    stty -echo
    et pour la réactiver
    stty echo

    Seconde astuce comment enregistrer la saisie d’entrée clavier, (comment récupérer ce que l’utilisateur va tapper au clavier)

    set variable=$<

    Ici, c’est le $< qui va récupérer la saisie

    Le tout illustré dans un exemple concret :

    # !/bin/csh
    Echo -n "Entrez votre identifiant : "
    Set ident = $<
    Stty -echo # désactive l’affichage des entrées claviers
    Echo -n "Entrez votre mot de passe : "
    Set mdp = $<
    Stty echo # réactivation de l’affichage
    Echo -n "tapez du texte pour vérifier la réactivation de l’affichage : "
    Set test = $<

    # maintenant on affiche le ident et mdp à ne pas faire biensur, si tu caches l’affichage c’est pas pour l’afficher derrière
    Echo "id : $ident et mdp : $mdp"

    # Et on constate aussi que $< permet la saisie par le terminal vers une variable script

    Set nom_variable = $<

    Voila j’espère que c’est deux petites astuces vous serviront :)

    Programmation en Shell Bash sous Linux

    Je met jamais d’espace et je croyais naïvement qu’il n’en fallait pas ;)

    Désolé pour le bruit ;)

    Programmation en Shell Bash sous Linux

    Bravo pour ce tuto, je me disais qu’un jour, il faudrait que je m’y mette car cela est parfois bien pratique. Juste deux petites coquilles au passage à la fin du tuto :
    "je vous conseille la lecture de cet excellent livre dont deux chapitres sont disponibles au format PDF.
    A la vitesse des tutos qui sortent, il me faut des vacances que pour cela ! Merci du partage.

    Programmation en Shell Bash sous Linux

    Bein je ne vois pas trop ce que tu veux dire.

    Si c’est l’espace entre le point d’exclamation et le slash, c’est normal (mais pas obligatoire)

    Sinon, je ne vois pas d’espace entre le dieze et le point d’exclamation.

    Programmation en Shell Bash sous Linux

    Il y a un probleme avec "# ! /bin/bash" a cause de spip (l’espace en trop :/)