Chapitre 7. Les instructions de condition

Table des matières

1. Introduction de if
1.1. Généralité
1.2. Simples applications de if
2. L'emploi avancé de if
2.1. les blocs if/then/else
2.2. Les blocs if/then/elif/else
2.3. Les instructions if imbriquées
2.4. Opérations booléennes
2.5. Emploi de l'instruction exit et du if
3. Utiliser les instructions case
3.1. Les conditions simplifiées
3.2. Exemple de script d'initialisation
4. Résumé
5. Exercices

Résumé

Dans ce chapitre nous traiterons de l'emploi de conditions dans les scripts Bash. Ceci comprend les sujets suivants:

  • L'instruction if

  • L'usage du statut d'exécution d'une commande

  • Comparer et tester les entrées et des fichiers

  • les blocs if/then/else

  • Les blocs if/then/elif/else

  • Utiliser et tester les paramètres positionnels

  • Les instructions if imbriquées

  • Les expressions booléennes

  • Utiliser les instructions case

1. Introduction de if

1.1. Généralité

A certain moment vous pouvez vouloir donner une alternative au traitement effectué par le script, en fonction de l'échec ou la réussite d'une commande. Le bloc if permet de spécifier de telles conditions.

La syntaxe la plus compacte de la commande if est:

if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi

La liste TEST-COMMAND est exécutée, et si elle retourne le statut zéro, la liste CONSEQUENT-COMMANDS est exécutée. Le statut retourné est le statut d'exécution de la dernière commande exécutée, ou zéro si aucune condition n'est vraie.

Le TEST-COMMAND souvent comprend des comparaisons de numériques ou de chaînes, mais cela peut être aussi toute commande qui retourne un statut à zéro quand elle s'est bien exécutée et d'autres valeurs en cas d'échec. Une expression unaire est souvent utilisée pour examiner le statut d'un fichier. Si l'argument FILE d'une de ces primitives est de la forme /dev/fd/N, alors le descripteur de fichier « N » est contrôlé. stdin, stdout et stderr et leur descripteur de fichier respectif peuvent aussi être employés dans les tests.

1.1.1. Expressions employées avec if

Le tableau ci-dessous contient un aperçu de ce qu'on appelle « primitives » et qui servent aux commandes TEST-COMMAND ou liste de commandes. Ces primitives sont mises entre crochets pour indiquer le test d'une expression conditionnelle..

Tableau 7.1. Expressions primitives

Primitivessens
[ -a FICHIER ]Vrai si FICHIER existe.
[ -b FICHIER ]Vrai si FICHIER existe et est un fichier de type bloc.
[ -c FICHIER ]Vrai si FICHIER existe et est un fichier de type caractère.
[ -d FICHIER ]Vrai si FICHIER existe et est de type répertoire.
[ -e FICHIER ]Vrai si FICHIER existe.
[ -f FICHIER ]Vrai si FICHIER existe et est un fichier régulier.
[ -g FICHIER ]Vrai si FICHIER existe et son bit SGID est positionné.
[ -h FICHIER ]Vrai si FICHIER existe et est un lien symbolique.
[ -k FICHIER ]Vrai si FICHIER existe et son bit collant est positionné.
[ -p FICHIER ]Vrai si FICHIER existe et est un tube nommé (FIFO).
[ -r FICHIER ]Vrai si FICHIER existe et est lisible.
[ -s FICHIER ]Vrai si FICHIER existe et a une taille supérieure à zéro.
[ -t FD ]Vrai si le descripteur de fichier FD est ouvert et qu'il se réfère à un terminal.
[ -u FICHIER ]Vrai si FILE existe et son bit SUID (Set User ID) est positionné.
[ -w FICHIER ]Vrai si FICHIER existe et peut être écrit.
[ -x FICHIER ]Vrai si FICHIER existe et est exécutable.
[ -O FICHIER ]Vrai si FICHIER existe et appartient à l'identifiant effectif de l'utilisateur.
[ -G FICHIER ]Vrai si FICHIER existe et appartient à l'identifiant effectif du groupe.
[ -L FICHIER ]Vrai si FICHIER existe et est un lien symbolique.
[ -N FICHIER ]Vrai si FICHIER existe et qu'il a été modifié depuis qu'il a été lu.
[ -S FICHIER ]Vrai si FICHIER existe et est un connecteur réseau (socket).
[ FILE1 -nt FILE2 ]Vrai si FILE1 a été modifié plus récemment que FILE2, ou si FILE1 existe et FILE2 n'existe pas.
[ FILE1 -ot FILE2 ]Vrai si FILE1 est plus ancien que FILE2, ou si FILE2 existe et FILE1 non.
[ FILE1 -ef FILE2 ]Vrai si FILE1 et FILE2 se réfère à la même entité et même numéro d'inode.
[ -o OPTIONNAME ]Vrai si l'option Shell « OPTIONNAME » est activée.
[ -z STRING ]Vrai si la longueur de « STRING » est zéro.
[ -n STRING ] or [ STRING ]Vrai si la longueur de « STRING » n'est pas zéro.
[ STRING1 == STRING2 ] Vrai si les chaînes sont identiques. « = » peut être employé au lieu de « == » pour une stricte compatibilité POSIX.
[ STRING1 != STRING2 ] Vrai si les chaînes ne sont pas égales.
[ STRING1 < STRING2 ] Vrai si « STRING1 » précède « STRING2 » selon le lexique du paramétrage local.
[ STRING1 > STRING2 ] Vrai si « STRING1 » suit « STRING2 » selon le lexique du paramétrage local.
[ ARG1 OP ARG2 ]« OP » est -eq, -ne, -lt, -le, -gt ou -ge. Ces opérateurs arithmétiques binaires renvoient vrai si « ARG1 » est égal, non égal, inférieur, supérieur ou égal, supérieur, ou supérieur ou égal à « ARG2 », respectivement. « ARG1 » et « ARG2 » sont des entiers.

Les expressions peuvent être combinées avec les opérateurs suivants dans l'ordre de leur préséance:

Tableau 7.2. Combinaison d'expressions

OpérationEffet
[ ! EXPR ]Vrai si EXPR est faux.
[ ( EXPR ) ]Renvoie la valeur de EXPR. Ceci peut être utilisé pour modifier la préséance normale des opérateurs.
[ EXPR1 -a EXPR2 ]Vrai si EXPR1 et EXPR2 sont vrai..
[ EXPR1 -o EXPR2 ]Vrai si soit EXPR1 ou EXPR2 est vrai.

L'intégrée [ (ou test) évalue les expressions conditionnelles en utilisant un jeux de règles basé sur le nombre d'arguments. Plus d'information sur ce sujet se trouve dans la documentation Bash. Tout comme le if est terminé par fi, le crochet ouvrant devrait être fermé après que les conditions aient été listées.

1.1.2. Les commandes qui suivent l'instruction then

La liste CONSEQUENT-COMMANDS qui suit l'instruction then peut être toute commande UNIX valide , tout programme exécutable, tout script Shell exécutable ou toute instruction Shell, à l'exception de fi. Il est important de se rappeler que then et fi sont considérés comme des instructions à part entière dans le Shell. De ce fait, quand elles sont fournies à la ligne de commande, elles sont séparées par un point-virgule.

Dans un script, les différentes parties de l'instruction if sont d'ordinaire bien séparées. Ci-dessous, quelques exemples.

1.1.3. Contrôler des fichiers

Le premier exemple contrôle l'existence d'un fichier:

anny ~> cat msgcheck.sh
#!/bin/bash

echo "Ce script vérifie si le fichier des messages existe."
echo "Vérification..."
if [ -f /var/log/messages ]
  then
    echo "/var/log/messages existe."
fi
echo
echo "...fait."

anny ~> ./msgcheck.sh
Ce script vérifie si le fichier des messages existe.
Vérification...
/var/log/messages existe.

...fait.

1.1.4. Vérifier des options Shell

A ajouter dans vos fichier de configuration Bash:

# Ces lignes affichent un message si l'option noclobber option est positionnée:

if [ -o noclobber ]
  then
	echo "Vos fichiers sont protégés contre une réécriture accidentelle du fait d'une redirection."
fi

L'environnement

L'exemple ci-dessus fonctionnera si il est soumis à la ligne de commande:

anny ~> if [ -o noclobber ] ; then echo ; echo "Vos fichiers sont protégés contre une réécriture." ; echo ; fi

Vos fichiers sont protégés contre une réécriture.

anny ~>

Cependant, si vous employez les tests de conditions qui dépendent de l'environnement, vous pourriez obtenir des résultats variables alors que vous exécutez la même commande dans un script, parce que le script ouvrira un nouveau Shell, dans lequel les variables et options attendues pourraient ne pas être définies automatiquement.

1.2. Simples applications de if

1.2.1. Tester le statut d'exécution

La variable ? stocke le statut d'exécution de la commande précédemment exécutée (le processus le plus récemment achevé au premier plan).

L'exemple suivant montre un simple test:

anny ~> if [ $? -eq 0 ]
More input> then echo 'That was a good job!'
More input> fi
That was a good job!

anny ~>

L'exemple suivant démontre que TEST-COMMANDS pourrait être toute commande UNIX qui retourne un statut, et le if à son tour renvoie un statut à zéro:

anny ~> if ! grep $USER /etc/passwd
More input> then echo "votre compte utilisateur ne se trouve pas sur le système local"; fi
votre compte utilisateur ne se trouve pas sur le système local

anny > echo $?
0

anny >

Le même résultat peut être obtenu comme ceci:

anny > grep $USER /etc/passwd

anny > if [ $? -ne 0 ] ; then echo "pas un compte local" ; fi
pas un compte local

anny >

1.2.2. Comparaisons numériques

Les exemples ci-dessous emploient des comparaisons numériques:

anny > num=`wc -l work.txt`

anny > echo $num
201

anny > if [ "$num" -gt "150" ]
More input> then echo ; echo "vous avez assez travaillé pour aujourd'hui."
More input> echo ; fi

vous avez assez travaillé pour aujourd'hui.


anny >

Ce script est exécuté par cron chaque dimanche. Si le numéro de semaine est pair, cela vous rappelle le passage des éboueurs :

#!/bin/bash

# Calculer le numéro de semaine à partir de la commande date:

WEEKOFFSET=$[ $(date +"%V") % 2 ]

# Tester si il y a un reste.  Si pas de reste, c'est une semaine paire donc envoyer un message.
# Sinon, ne rien faire.

if [ $WEEKOFFSET -eq "0" ]; then
  echo "Dimanche soir, les éboueurs passent." | mail -s "Les éboueurs passent" your@your_domain.org

1.2.3. Comparaisons de chaînes

Un exemple de comparaison de chaînes avec le test de l'identifiant utilisateur:

if [ "$(whoami)" != 'root' ]; then
        echo "Vous ne détenez pas la permission de lancer $0 en tant que non administrateur."
        exit 1;
fi

Avec Bash, vous pouvez raccourcir ce type de construction. L'équivalent compact du test ci-dessus est ce qui suit:

[ "$(whoami)" != 'root' ] && ( echo vous êtes connectés avec un compte non administrateur; exit 1 )

Similaire à l'expression « && » qui indique quoi faire si le test s'avère vrai, « || » spécifie quoi faire si le test est faux.

Une expression régulière peut être employée aussi dans les comparaisons:

anny > genre="féminin"

anny > if [[ "$genre" == f* ]]
More input> then echo "Très honoré, Madame."; fi
Très honoré, Madame.

anny >

Les vrais Programmeurs

La plupart des programmeurs préféreront employer l'intégrée test qui est équivalent à l'emploi du crochet de comparaison, comme ceci:

test "$(whoami)" != 'root' && (echo vous êtes connectés avec un compte non administrateur; exit 1)

Voir les pages info de Bash pour plus de détails sur la correspondance de patron avec les blocs « (( EXPRESSION )) » et « [[ EXPRESSION ]] ».

2. L'emploi avancé de if

2.1. les blocs if/then/else

2.1.1. Exemple simple

Voici la construction à employer pour que le cours du traitement s'oriente d'une façon si la commande if renvoie vrai, et d'une autre si elle renvoie faux. Un exemple:

freddy scripts> genre="masculin"

freddy scripts> if [[ "$genre" == "f*" ]]
More input> then echo "Très honoré, Madame."
More input> else echo "Comment se fait-il que le verre de Madame  soit vide?"
More input> fi
Comment se fait-il que le verre de Madame  soit vide?

freddy scripts>

De même que la liste CONSEQUENT-COMMANDS suivant le then, la liste ALTERNATE-CONSEQUENT-COMMANDS suivant le else peut contenir toute commande de style UNIX qui retourne un statut d'exécution.

Un autre exemple, tiré de celui de la Section 1.2.1, « Tester le statut d'exécution »:

anny ~> su -
Password:
[root@elegance root]# if ! grep ^$USER /etc/passwd 1> /dev/null
> then echo "votre compte utilisateur ne se trouve pas sur le système local"
> else echo "votre compte utilisateur ne se trouve pas sur le système local"
> fi
votre compte utilisateur se trouve dans /etc/passwd file
[root@elegance root]#

Nous permutons vers le compte root pour montrer l'effet du else - votre root est d'ordinaire un compte local tandis que votre compte personnel peut être géré par un système central, tel qu'un serveur LDAP.

2.1.2. Contrôle des paramètres de la ligne de commande

Au lieu de déclarer une variable puis d'exécuter un script, il est fréquemment plus élégant de mettre la valeur de la variable dans la ligne de commande.

Pour ce faire nous employons les paramètres positionnels $1, $2, ..., $N. $# mémorise le nombre de paramètres de la ligne de commande. $0 mémorise le nom du script.

Voici un exemple simple:

Figure 7.1. Test d'une ligne de commande avec if

Simple bloc if/then/else/fi : if [ "$1" == poisson ]; then echo "Tux adore ça"; else echo "Tux veut du poisson!"; fi

Voici un autre exemple avec 2 paramètres:

anny ~> cat weight.sh
#!/bin/bash

# Ce script affiche un message au sujet de votre poids si vous donnez votre
# poids en kilos et votre taille en centimètres.

weight="$1"
height="$2"
idealweight=$[$height - 110]

if [ $weight -le $idealweight ] ; then
  echo "Vous devriez manger un peu plus gras."
else
  echo "Vous devriez manger un peu plus de fruits."
fi

anny ~> bash -x weight.sh 55 169
+ weight=55
+ height=169
+ idealweight=59
+ '[' 55 -le 59 ']'
+ echo 'Vous devriez manger un peu plus gras.'
Vous devriez manger un peu plus gras.

2.1.3. Tester le nombre de paramètres

L'exemple suivant montre comment changer le script précédent de sorte qu'il affiche un message si plus ou moins de 2 paramètres sont donnés:

anny ~> cat weight.sh
#!/bin/bash

# Ce script affiche un message au sujet de votre poids si vous donnez votre
# poids en kilos et votre taille en centimètres.

if [ ! $# == 2 ]; then
  echo "Usage: $0 poids_en_kilos taille_en_centimètres"
  exit
fi

weight="$1"
height="$2"
idealweight=$[$height - 110]

if [ $weight -le $idealweight ] ; then
  echo "Vous devriez manger un peu plus gras."
else
  echo "Vous devriez manger un peu plus de fruits."
fi

anny ~> weight.sh 70 150
Vous devriez manger un peu plus de fruits.

anny ~> weight.sh 70 150 33
Usage: ./weight.sh poids_en_kilos taille_en_centimètres

Le premier paramètre est référencé par $1, le second par $2 et ainsi de suite. Le nombre total de paramètres est stocké dans $#.

Consulter la Section 2.5, « Emploi de l'instruction exit et du if » pour voir une façon plus élégante d'afficher des messages de mode d'emploi.

2.1.4. Test de l'existence d'un fichier

Le test est fait dans beaucoup de scripts, parce que il n'y a pas d'intérêt à lancer un programme si vous savez qu'il ne va pas fonctionner:

#!/bin/bash

# Ce script donne des informations au sujet d'un fichier.

FILENAME="$1"

echo "Properties for $FILENAME:"

if [ -f $FILENAME ]; then
  echo "Size is $(ls -lh $FILENAME | awk '{ print $5 }')"
  echo "Type is $(file $FILENAME | cut -d":" -f2 -)"
  echo "Inode number is $(ls -i $FILENAME | cut -d" " -f1 -)"
  echo "$(df -h $FILENAME | grep -v Mounted | awk '{ print "On",$1", \
which is mounted as the",$6,"partition."}')"
else
  echo "Le fichier est non-existant."
fi

Notez que le fichier est référencé au moyen d'une variable; dans ce cas c'est le premier paramètre du script. Alternativement, quand aucun paramètre n'est donné, l'emplacement du fichier est mémorisé généralement dans une variable au début du script, et son contenu est connu par l'invocation de la variable. De sorte que si vous voulez changer le nom d'un fichier dans un script, vous n'avez que à le modifier une fois.

2.2. Les blocs if/then/elif/else

2.2.1. Généralité

C'est la forme complète de l'instruction if:

if TEST-COMMANDS; then

CONSEQUENT-COMMANDS;

elif MORE-TEST-COMMANDS; then

MORE-CONSEQUENT-COMMANDS;

else ALTERNATE-CONSEQUENT-COMMANDS;

fi

La liste TEST-COMMANDS est exécutée, et si son statut d'exécution est zéro, la liste CONSEQUENT-COMMANDS est exécutée. Si TEST-COMMANDS renvoie un statut différent de zéro, chaque liste elif est exécutée à son tour, et si leur statut d'exécution est zéro, le MORE-CONSEQUENT-COMMANDS correspondant est exécuté et la commande se termine. Si else est suivi par une liste ALTERNATE-CONSEQUENT-COMMANDS, et que la dernière commande dans le dernier if ou elif renvoie un statut différent de zéro, alors ALTERNATE-CONSEQUENT-COMMANDS est exécuté. Le statut retourné est le statut d'exécution de la dernière commande exécutée, ou zéro si aucune condition n'est vraie.

2.2.2. Exemple

Ceci est un exemple que vous pouvez mettre dans votre crontab pour une exécution quotidienne:

anny /etc/cron.daily> cat disktest.sh
#!/bin/bash

# Ce script fait un test très simple pour contrôler l'espace disque.

space=`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -`
alertvalue="80"

if [ "$space" -ge "$alertvalue" ]; then
  echo "Au moins un de mes disques est bientôt plein!" | mail -s "daily diskcheck" root
else
  echo "Espace disque correct" | mail -s "daily diskcheck" root
fi

2.3. Les instructions if imbriquées

Comprise dans une instruction if on peut inclure une autre instruction if. Vous pouvez inclure autant de niveaux de if imbriqués que vous pouvez appréhender logiquement.

Voici un exemple testant l'année bissextile:

anny ~/testdir> cat testleap.sh
#!/bin/bash
# Ce script teste si nous sommes dans une année bissextile ou pas.

year=`date +%Y`

if [ $[$year % 400] -eq "0" ]; then
  echo "This is a leap year.  Février a 29 jours."
elif [ $[$year % 4] -eq 0 ]; then
        if [ $[$year % 100] -ne 0 ]; then
          echo "Année bissextile, Février a 29 jours."
        else
          echo "Année non bissextile.  Février a 28 jours."
        fi
else
  echo "Année non bissextile.  Février a 28 jours."
fi

anny ~/testdir> date
Tue Jan 14 20:37:55 CET 2003

anny ~/testdir> testleap.sh
Année non bissextile.

2.4. Opérations booléennes

Le script ci-dessus peut être abrégé avec les opérateurs booléens « AND » (&&) et « OR » (||).

Figure 7.2. Exemple employant les opérateurs booléens

year=`date +%Y`; if (( ("$year" % 400) == "0" )) || (( ("$year" % 4 == "0") && ("$year" % 100 != "0") )); then echo "Année bissextile."; else echo "Année non bissextile"; fi

Nous employons le double crochet pour tester les expressions arithmétiques, voir la Section 4.6, « L'expansion arithmétique ». Ceci est équivalent à l'instruction let. Ici, vous allez être bloqué si vous employez les crochets, si vous essayez quelque chose de la sorte $[$year % 400], parce que ici, les crochets ne représentent pas une vraie commande mais eux-mêmes.

Parmi d'autres éditeurs, gvim est l'un de ceux qui supporte les codes de couleur selon le format de fichier; de tel éditeurs sont pratiques pour pister les erreurs d'écriture.

2.5. Emploi de l'instruction exit et du if

Nous avons déjà rencontré l'instruction exit dans la Section 2.1.3, « Tester le nombre de paramètres ». Il achève l'exécution du script. Il est plus souvent utilisé si l'entrée requise de l'utilisateur est incorrecte, si une instruction a échouée ou si une autre erreur intervient.

L'instruction exit admet un argument optionnel. Cet argument est le code sous forme d'entier du statut d'exécution, qui est renvoyé au parent et stocké dans la variable $?.

Un argument à zéro signifie que le script s'est exécuté correctement. Tout autre valeur peut être employée par le programmeur pour renvoyer divers messages au parent, afin que divers traitements soit activés selon l'échec ou la réussite du processus enfant. Si aucun argument n'est donné à la commande exit, le Shell parent exploite la valeur courante de la variable $?.

Ci-dessous un exemple avec un script penguin.sh légèrement adapté, lequel renvoie son statut d'exécution vers son parent, feed.sh:

anny ~/testdir> cat penguin.sh
#!/bin/bash
                                                                                                 
# Ce script vous laisse présenter divers menus à Tux.  Il ne sera heureux que
# quand il aura du poisson.  Nous avons aussi ajouté un dauphin et (logiquement) un chameau.
                                                                                                 
if [ "$menu" == "poisson" ]; then
  if [ "$animal" == "pingouin" ]; then
    echo "Hmmmmmm poisson... Tux heureux!"
  elif [ "$animal" == "dauphin" ]; then
    echo "Pweetpeettreetppeterdepweet!"
  else
    echo "*prrrrrrrt*"
  fi
else
  if [ "$animal" == "pingouin" ]; then
    echo "Tux déteste ça.  Tux veut du poisson!"
    exit 1
  elif [ "$animal" == "dauphin" ]; then
    echo "Pweepwishpeeterdepweet!"
    exit 2
  else
    echo "Voulez-vous lire cette affiche?!"
    exit 3
  fi
fi

Ce script est appelé depuis le suivant, qui donc exporte ses variables menu et animal:

anny ~/testdir> cat feed.sh
#!/bin/bash
# Ce script procède selon le statut d'exécution renvoyé par penguin.sh
                                                                                                 
export menu="$1"
export animal="$2"
                                                                                                 
feed="/nethome/anny/testdir/penguin.sh"
                                                                                                 
$feed $menu $animal
                                                                                                 
case $? in
                                                                                                 
1)
  echo "Gaffe: Vous feriez mieux de lui donner du poisson, avant qu'il ne s'énerve..."
  ;;
2)
  echo "Gaffe: C'est à cause de gens comme vous qu'il quitte la terre tout le temps..."
  ;;
3)
  echo "Gaffe: Achetez la nourriture que le zoo fournit pour les animaux, i@**@, comment pensez-vous que nous survivons?"
  ;;
*)
  echo "Gaffe: N'oubliez pas le guide!"
  ;;
esac
                                                                                                 
anny ~/testdir> ./feed.sh apple penguin
Tux déteste ça.  Tux veut du poisson!
Gaffe: Vous feriez mieux de lui donner du poisson, avant qu'il ne s'énerve...

Comme vous le voyez, le statut d'exécution peut être déterminé librement. Les commandes ont souvent une série de codes définis; voir le manuel du programmeur pour plus d'informations sur chaque commande.

3. Utiliser les instructions case

3.1. Les conditions simplifiées

Les instructions if imbriquées paraissent pratiques, mais dès que vous êtes confrontés à quelques variantes, cela engendre la confusion. Pour des conditions complexes, employez la syntaxe de case:

case EXPRESSION in CASE1) COMMAND-LIST;; CASE2) COMMAND-LIST;; ... CASEN) COMMAND-LIST;; esac

Chaque cas est une expression qui cible un patron. Les commandes COMMAND-LIST de la première correspondance trouvée sont exécutées. Le symbole « | » est employé pour séparer de multiples patrons, et l'opérateur « ) » termine la liste des patrons. Chaque case et ses commandes associées est appelé une clause. Chaque clause doit se terminer par « ;; ». Chaque instruction case est terminée par l'instruction esac.

Dans l'exemple, nous montrons l'emploi de case pour envoyer un message d'avertissement plus précis avec le script disktest.sh:

anny ~/testdir> cat disktest.sh
#!/bin/bash

# Ce script fait un test très simple pour vérifier l'espace disque.

space=`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -`

case $space in
[1-6]*)
  Message="Tout est bon."
  ;;
[7-8]*)
  Message="Commencer à songer à faire de la place.  Il y a une partition qui est $space % pleine."
  ;;
9[1-8])
  Message="Dépêchez-vous avec ce nouveau disque..  Une partition est $space % pleine."
  ;;
99)
  Message="Je suis en train de me noyer!  Il y a une partition à $space %!"
  ;;
*)
  Message="Il semble que je tourne avec un espace disque inexistant..."
  ;;
esac

echo $Message | mail -s "disk report `date`" anny

anny ~/testdir>
Vous avez un nouveau mail.

anny ~/testdir> tail -16 /var/spool/mail/anny
From anny@octarine Tue Jan 14 22:10:47 2003
Return-Path: <anny@octarine>
Received: from octarine (localhost [127.0.0.1])
        by octarine (8.12.5/8.12.5) with ESMTP id h0ELAlBG020414
        for <anny@octarine>; Tue, 14 Jan 2003 22:10:47 +0100
Received: (from anny@localhost)
        by octarine (8.12.5/8.12.5/Submit) id h0ELAltn020413
        for anny; Tue, 14 Jan 2003 22:10:47 +0100
Date: Tue, 14 Jan 2003 22:10:47 +0100
From: Anny <anny@octarine>
Message-Id: <200301142110.h0ELAltn020413@octarine>
To: anny@octarine
Subject: disk report Tue Jan 14 22:10:47 CET 2003

Commencer à songer à faire de la place.  Il y a une partition qui est 87 % pleine.

anny ~/testdir>

Bien sûr vous pourriez avoir ouvert votre programme de messagerie pour contrôler le résultat; c'est juste pour montrer que le script envoie un mail correct avec « To: », « Subject: » and « From: » header lines.

Beaucoup plus d'exemples de l'instruction case peuvent être trouvés dans le répertoire des scripts d'initialisation de votre système. Le script de démarrage emploie un case start et stop pour démarrer ou arrêter les processus du système. Un exemple théorique peut être trouvé dans la section suivante.

3.2. Exemple de script d'initialisation

Les scripts d'initialisation ont souvent l'usage d'instructions case pour démarrer, arrêter et mettre en file d'attente les services du système. Voici un extrait du script qui démarre Anacron, un démon qui lance des commandes périodiquement avec une fréquence spécifiée en jours.

case "$1" in
        start)
            start
            ;;
         
        stop)
            stop
            ;;
         
        status)
            status anacron
            ;;
        restart)
            stop
            start
            ;;
        condrestart)
            if test "x`pidof anacron`" != x; then
                stop
                start
            fi
            ;;
         
        *)
            echo $"Usage: $0 {start|stop|restart|condrestart|status}"
            exit 1
 
esac

Les tâches à exécuter dans chaque cas, telles arrêter ou démarrer le démon, sont définies par des fonctions, dont la source est partiellement dans le fichier /etc/rc.d/init.d/functions. Voir le Chapitre 11, Fonctions pour plus d'explications.

4. Résumé

Dans ce chapitre nous avons appris comment écrire des conditions dans un script de sorte que différentes tâches puissent être menées à bien selon le succès ou l'échec d'une commande. L'action peut être déterminée par l'emploi de l'instruction if. Ceci permet d'effectuer des comparaisons de chaînes et arithmétique, et de tester le statut d'exécution, l'entrée et les fichiers requis par le script.

Un simple test if/then/fi souvent précède des commandes dans un script Shell afin d'éviter la production de résultat, de sorte que le script peut aisément être lancé en tâche de fond ou via l'outil cron. Les conditions trop complexes sont généralement intégrées à une instruction case.

A la suite d'un test positif, le script peut explicitement informer le parent par le biais du statut exit 0. A la suite d'un échec, tout autre nombre peut être retourné. Basé sur ce code retour, le programme parent peut déterminer l'action appropriée.

5. Exercices

Voici quelques idées pour vous lancer dans l'écriture de scripts if:

  1. Employez un bloc if/then/elif/else qui affiche les informations du mois courant. Le script devrait afficher le nombre de jours du mois, et donner des informations sur l'année bissextile si le mois courant est février.

  2. Faire la même chose avec une instruction case et une variante de l'usage de la commande date.

  3. Modifier /etc/profile afin d'être accueilli par un message personnalisé quand vous vous connectez au système en tant que root.

  4. Modifier le script leaptest.sh dans Section 2.4, « Opérations booléennes » afin qu'il nécessite un paramètre, l'année. Tester que exactement un seul paramètre est passé.

  5. Ecrire un script appelé whichdaemon.sh qui vérifie que les démons httpd et init sont lancés sur votre système. Si un httpd est lancé, le script devrait afficher un message comme « Cette machine fait tourner un serveur WEB. » Employez ps pour contrôler les processus.

  6. Ecrire un script qui fait la sauvegarde de votre répertoire racine sur une machine distante en utilisant scp. Le script devrait écrire son rapport dans un fichier journal, par exemple ~/log/homebackup.log. Si vous n'avez pas de seconde machine pour y copier la sauvegarde, se servir de scp pour tester la copie sur la machine locale. Ceci nécessite des clés SSH entre 2 hôtes, ou sinon vous devez fournir un mot de passe. La création de clés SSH est expliquée dans le man ssh-keygen.

    Le script devrait se servir de tar cf pour la création de la sauvegarde et gzip ou bzip2 pour la décompression du fichier .tar. Mettre tous les noms de fichiers dans des variables. Mettre le nom du serveur distant et du répertoire distant dans une variable. Ce sera plus facile de réutiliser ce script ou d'y faire des modifications dans le futur.

    Le script devrait vérifier l'existence d'une archive compressée. Si elle existe, la supprimer d'abord pour éviter les messages d'erreur.

    Le script devrait aussi contrôler l'espace disque disponible. Avoir à l'esprit qu'à un moment donné vous pourrez avoir en même temps sur le disque les données dans votre répertoire racine, celles dans le fichier .tar et celle dans l'archive compressée. Si il n'y a pas assez d'espace, quitter avec un message d'erreur dans le fichier journal.

    Le script devrait nettoyer l'archive compressée avant de se terminer.