Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Programmation shell sous Unix/Linux
  3. Comment faire... (synthèse)
Extrait - Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
Extraits du livre
Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
2 avis
Revenir à la page d'achat du livre

Comment faire... (synthèse)

Présentation

Ce chapitre propose des solutions permettant de résoudre différentes problématiques. Nous présentons ici les techniques les plus utilisées, la liste n’étant pas exhaustive.

Informations

Lorsque les exemples de ce chapitre sont saisis en ligne de commande, le symbole $ représente le prompt du shell (PS1) et le symbole > représente le prompt secondaire du shell (PS2 - attente de la suite de la commande) (cf. chapitre Paramétrage de l’environnement de travail - Variables d’environnement).

Les expressions étendues du shell sont utilisées à plusieurs reprises dans ce chapitre. Il est rappelé qu’en bash, l’option extglob doit être activée pour que les expressions étendues fonctionnent (cf. chapitre Mécanismes essentiels du shell - Substitution de noms de fichiers) :

shopt -s extglob 

Lorsque les méthodes de résolution présentées fonctionnent pour certains shells uniquement, ces derniers sont spécifiés.

Modèles de noms de fichiers

Objectif

Travailler sur des noms de fichiers correspondant à un modèle.

Exemple

Lister les fichiers ayant l’extension .php ou .sh.

Première méthode

Avec les caractères de substitution de noms de fichiers :

$ ls *.php *.sh  
prog.php  test.sh 

(cf. chapitre Mécanismes essentiels du shell - Substitution de noms de fichiers) 

Deuxième méthode (ksh, bash)

Avec les caractères de substitution de noms de fichiers et l’utilisation des expressions étendues :

$ ls *.@(php|sh)  
prog.php  test.sh 

(cf. chapitre Mécanismes essentiels du shell - Substitution de noms de fichiers) 

Troisième méthode

Utilisation des expressions régulières avec grep :

$ ls | grep -E '(.php|.sh)$'  
prog.php  
test.sh 

L’option -E de la commande grep permet d’utiliser les expressions régulières étendues (cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes).

Tester le code retour d’une commande

Objectif

Effectuer un traitement en fonction du code retour d’une commande.

Exemple

Tester si l’utilisateur christie est défini dans le fichier /etc/passwd.

Première méthode

En utilisant la structure de contrôle if :

$ if grep -q christie /etc/passwd ; then  
>    echo "L'utilisateur christie existe"  
> fi 

Ce qui peut également s’écrire comme ceci :

$ grep -q christie /etc/passwd  
$ if [[ $? eq 0 ]]        # ksh, bash (Bourne/Posix: utiliser [ ] ) 
> then  
>    echo "L'utilisateur christie existe"  
> fi 

(cf. chapitre Les bases de la programmation shell - Les structures de contrôle et Exécution de tests)

Deuxième méthode

En utilisant les opérateurs logiques du shell (&&,||) :

$ grep -q christie /etc/passwd && echo "L'utilisateur christie 
existe" 
L'utilisateur christie existe 

(cf. chapitre Les bases de la programmation shell - Les opérateurs du shell)

Test d’égalité entre deux chaînes

Objectif

Tester si une variable est strictement égale à une valeur.

Exemple

La variable choix a-t-elle pour valeur "oui" ?

Première méthode (ksh, bash)

Utilisation de la commande de test [[ ]] :

$  [[ $choix = oui ]]  && echo '$choix vaut oui' 

(cf. Les bases de la programmation shell - Exécution de tests)

Deuxième méthode

Utilisation de la commande de test [ ] :

$ [ "$choix" = oui ]  && echo '$choix vaut oui' 

Contrairement à la commande [[ ]], la commande [ ] provoque une erreur si l’expression $choix est vide et non placée entre guillemets (les guillemets n’empêchant pas la substitution de la variable).

(cf. Les bases de la programmation shell - Exécution de tests)

Troisième méthode

Utilisation de la structure de contrôle case :

$ case $choix in 
>     oui) echo '$choix vaut oui' ;; 
>       *) ...
> esac 

(cf. chapitre Les bases de la programmation shell - Les structures de contrôle)

Quatrième méthode

Utilisation de la commande expr et d’une expression régulière :

$ expr $choix : 'oui$' >/dev/null  && echo '$choix vaut oui' 

Avec expr, le caractère ˆ est implicite au niveau de l’expression régulière (équivalent à ’ˆoui$’).

(cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes)

Cinquième méthode

Utilisation de la commande grep et d’une expression régulière :

$ echo $choix | grep -qE 'ˆoui$' && echo '$choix vaut oui' 

(cf. chapitre Les expressions régulières - Exploitation...

Test d’inégalité entre deux chaînes

Objectif

Tester si une variable est différente d’une valeur.

Exemple

La variable choix est-elle différente de la valeur "oui" ?

Première méthode (ksh, bash)

Utilisation de la commande de test [[ ]] :

$  [[ $choix != oui ]]  && echo '$choix est different de oui' 

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Deuxième méthode

Utilisation de la commande de test [ ] :

$ [ "$choix" != oui ]  && echo '$choix est different de oui' 

Contrairement à la commande [[ ]], la commande [ ] provoque une erreur si l’expression $choix est vide et non placée entre guillemets (les guillemets n’empêchant pas la substitution de la variable).

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Troisième méthode

Utilisation de la commande grep avec option de négation -v et d’une expression régulière :

$ echo $choix | grep -aqE '^oui$' && echo 
'$choix est different de oui' 

(cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes)

Quatrième méthode

Utilisation de la commande awk et d’une expression régulière :

$ echo $choix | awk '$0  !~ /^oui$/ {print "$choix est different de oui"}' 

(cf. chapitre Le langage de programmation awk)

Correspondance d’une variable par rapport à un modèle

Objectif

Comparer la correspondance entre le contenu d’une variable et un modèle.

Exemple

Tester si la variable nombre contient une suite de chiffres, précédée d’un signe éventuel.

Première méthode (ksh, bash)

Utilisation de la commande [[ ]] avec les expressions étendues :

$ [[ $nombre = ?([+-])+([0-9]) ]]  && echo '$nombre est un nombre' 

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Deuxième méthode (ksh, bash)

Utilisation de la structure de contrôle case avec les expressions étendues :

$ case $nombre in  
>    ?([-+])+([0-9]) ) echo '$nombre est un nombre' ;;  
>    ...  
> esac 

(cf. chapitre Les bases de la programmation shell - Les structures de contrôle)

Autres méthodes

Les utilisateurs travaillant en Bourne shell ne pouvant utiliser les expressions étendues, ils devront recourir aux méthodes 4 à 6 de la section Test d’égalité entre deux chaînes avec les expressions régulières adéquates (expr, grep -E, awk).

Non-correspondance d’une variable par rapport à un modèle

Objectif

Comparer la non-correspondance entre le contenu d’une variable et un modèle.

Exemple

Vérifier que la variable chaine ne contient aucun chiffre.

Première méthode (ksh, bash)

Utilisation de la commande [[ ]] :

$ [[ $chaine != *[0-9]* ]]  && echo '$chaine ne contient aucun chiffre' 

Le modèle *[0-9]* représente une chaîne contenant au moins un chiffre.

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Deuxième méthode

Utilisation de la commande grep avec option de négation -v et d’une expression régulière :

$ echo $chaine | grep -qEv '[0-9]' && echo  
'$chaine ne contient pas de chiffre' 

(cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes)

Troisième méthode

Utilisation de la commande awk et d’une expression régulière :

$ echo $chaine | awk '$0 !~ /[0-9]/ {print "$chaine ne contient 
pas de chiffre"}' 

(cf. chapitre Le langage de programmation awk)

Retirer le début ou la fin d’une chaîne

Objectif

Retirer la fin d’une chaîne de caractères.

Exemple

Retrait de l’extension d’un nom de fichier.

Initialisation de la variable fichier

$ fichier=rapport.docx 

Première méthode (ksh, bash)

Utiliser les caractères de substitution de variables :

$ echo ${fichier%.*}  
rapport 

Le caractère % permet de retirer la partie la plus courte à droite correspondant à .*.

(cf. chapitre Aspects avancés de la programmation shell - Manipulation de variables) 

Deuxième méthode

Utilisation de la commande expr :

$ expr $fichier : '\(.*\)\..*$'   
rapport 

La commande expr affiche la chaîne qui correspond au parenthésage.

(cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes)

Troisième méthode

Utilisation de la commande sed :

$ echo $fichier | sed 's/\.[ˆ.]*$//'  
rapport 

La partie extension est recherchée et remplacée par du vide.

(cf. chapitre Les expressions régulières - Exploitation des expressions régulières par les commandes)

Quatrième méthode

Utilisation de la fonction sub de awk et d’une expression régulière :

$ echo $fichier | awk '{ sub(/\..+$/,"",$0) ; print $0 }'  
rapport 

(cf. chapitre Le langage de programmation awk - Fonctions intégrées)

Cinquième méthode

Utilisation de la commande basename :

$ basename  $fichier .docx  
rapport 

Cette commande est dédiée aux noms de fichiers : le deuxième argument optionnel correspond au suffixe à retirer.

Calculer la longueur d’une chaîne

Initialisation de la variable

$ mot=arbre 

Première méthode (bash, ksh)

Utiliser la variable spéciale du ksh et bash :

$ echo "${#mot}" 
5 

(cf. chapitre Aspects avancés de la programmation shell - Manipulation de variables) 

Deuxième méthode

Utiliser la commande wc :

$ echo -n "$mot" | wc -c  
5 

(cf. chapitre Les commandes filtres - Traitements de données - Comptage de lignes, de mots et de caractères : wc)

Troisième méthode

Utiliser la commande expr qui affiche le nombre de caractères correspondant à l’expression régulière :

$ expr "$mot" : '.*'  
5 

(cf. chapitre Les expressions régulières - La commande expr)

Quatrième méthode

Utiliser la fonction length() de la commande awk :

$ echo $mot | awk '{print length($0)}'  
5 

(cf. chapitre Le langage de programmation awk - Fonctions intégrées)

Récupérer le champ d’une ligne

Objectif

Récupérer le champ d’une ligne qui possède un séparateur de champs.

Exemple

Récupérer le troisième champ de la variable ligne :

$ ligne='Newton|Christine|London'  

Première méthode

En utilisant la commande cut :

$ echo $ligne  | cut -d'|' -f3  
London 

Le caractère séparateur | (option -d) doit être protégé par des apostrophes pour que le shell ne l’interprète pas comme un tube de communication.

(cf. chapitre Les commandes filtres - Traitement de données)

Deuxième méthode

En utilisant la commande awk :

$ echo $ligne | awk -F'|' '{print $3}'  
London 

Le caractère séparateur | (option -F) doit être protégé par des apostrophes pour que le shell ne l’interprète pas comme un tube de communication.

(cf. chapitre Le langage de programmation awk - Variables spéciales)

Troisième méthode

En utilisant la commande read du shell, avec modification de la variable IFS.

En ksh :

$ IFS="|"  
$ echo "$ligne" | read nom prenom ville  
$ echo $ville  
London 

Il ne faut pas oublier de mettre des guillemets autour de la variable ligne car elle contient le caractère | qui est maintenant un délimiteur (comme l’était l’espace auparavant). Il ne faut pas que ce caractère soit interprété puis transformé par le shell, il faut qu’il passe dans le tube. La commande read, qui est une commande interne, est interprétée par le shell courant en ksh ; les variables nom, prenom et ville sont donc disponibles dans le shell courant après exécution de read. Nous allons voir ci-dessous que le bash ne fonctionne pas de la même...

Ne pas afficher certaines lignes d’un flux

Objectif

Ne pas afficher certaines lignes d’un fichier ou d’un flux de données.

Exemple

Ne pas afficher les lignes du fichier fic.txt qui commencent par un dièse.

$ cat fic.txt  
# commentaire A  
instruction 1  
# commentaire B  
instruction 2 

Première méthode

En utilisant grep et son option -v :

$ grep -v 'ˆ#' fic.txt  
instruction 1  
instruction 2 

(cf. chapitre Les commandes filtres - Visualisation de données)

Deuxième méthode

En utilisant sed avec son action d (delete) :

$ sed '/ˆ#/d' fic.txt  
instruction 1  
instruction 2 

(cf. chapitre La commande sed - Utilisation de la commande sed)

Troisième méthode

Utilisation de awk et d’une expression régulière :

$ awk '$0 !~ /ˆ#/ { print }' fic.txt  
instruction 1  
instruction 2 

(cf. chapitre Le langage de programmation awk)

Tests numériques

Objectif

Effectuer des tests numériques sur des variables contenant des nombres.

Exemple

Tester si la variable nombre est inférieure à 100.

Première méthode (ksh, bash)

Utiliser la commande de test [[ ]] :

$ [[ $nombre -lt 100 ]] && echo '$nombre < 100' 

Attention à ne pas utiliser les opérateurs =, !=, < et > de la commande [[ ]] qui font des tests lexicographiques (comparaison de chaînes) et non numériques.

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Deuxième méthode

Utiliser la commande de test [ ] :

$ [ $nombre -lt 100 ] && echo '$nombre < 100' 

Attention à ne pas utiliser les opérateurs = et != de la commande [ ] qui font des tests lexicographiques (comparaison de chaînes) et non numériques.

(cf. chapitre Les bases de la programmation shell - Exécution de tests)

Troisième méthode (ksh, bash)

Utiliser la commande arithmétique (( )) :

$ (( $nombre < 100 )) && echo  '$nombre < 100' 

(cf. chapitre Les bases de la programmation shell - L’arithmétique)

Quatrième méthode

Utiliser la commande expr :

$ expr $nombre \< 100 > /dev/null && echo  '$nombre < 100' 

La commande expr n’est pas la plus confortable car il faut protéger les caractères spéciaux du shell et éliminer un affichage inutile.

(cf. chapitre Les bases de la programmation shell - L’arithmétique)

Calculs

Objectif

Faire des calculs arithmétiques.

Exemple

Multiplier la variable nombre par 100.

Première méthode (ksh, bash)

Utiliser la substitution d’expressions arithmétiques :

$ nombre=$(( $nombre * 100 )) 

ou

$ nombre=$(( nombre * 100 )) 

Deuxième méthode (ksh, bash)

Utiliser la commande arithmétique (( )) :

$ (( $nombre * 100 )) 

(cf. chapitre Les bases de la programmation shell - L’arithmétique)

Troisième méthode

Utiliser la commande expr :

$ expr $nombre \* 100 

La commande expr n’est pas la plus confortable car il faut protéger les caractères spéciaux du shell et éliminer un affichage inutile.

(cf. chapitre Les bases de la programmation shell - L’arithmétique)

Des exemples de calcul sur les nombres flottants sont présentés au chapitre Les bases de la programmation shell - Arithmétique sur les flottants.

Lancer un script d’un autre langage à partir d’un shell

Objectif

Exécuter un script Perl et un script Python à partir d’un script shell.

Le script Perl

$ nl scriptperl.pl  
    1  #! /usr/bin/perl  
 
    2  print "Je suis un script Perl" ;  
    3  exit 0 ; 

Le script Python

$ nl scriptpython.py  
    1  #! /usr/bin/python  
 
    2  print "Je suis un script Python"  
    3  exit(0) 

Le script shell

$ nl test_scripts.sh  
 
    1  # Exécution du script Python  
    2  if scriptpython.py > /dev/null  
    3  then  
    4    echo "Script Python terminé avec succès"  
    5  else  
    6    echo "Script Python terminé avec échec"  
    7  fi  
 
    8  # Exécution du script Perl  
    9  if scriptperl.pl > /dev/null  
   10  then  
   11    echo "Script Perl terminé avec succès"  
   12  else  
   13    echo "Script Perl terminé avec échec"  
   14  fi 

Environnement

Dans notre exemple, les scripts possèdent le droit d’exécution et sont accessibles au travers de la variable PATH.

$ ls -l  
total 20  
-rwxrw-r-- 1 christie ociensa  60 15 juin  19:03 scriptperl.pl 
-rwxrw-r-- 1 christie ociensa  61 15 juin  19:04 scriptpython.py 
-rwxrw-r-- 1 christie ociensa 310 15 juin  19:07 test_scripts.sh 

Exécution

$ test_scripts.sh  
Script Python terminé avec succès  
Script Perl...

Accéder à une base MySQL à partir d’un shell

Objectif

Lancer une commande SQL SELECT à partir d’un script et exploiter son résultat, puis lancer la sauvegarde d’une base de données MySQL.

Le script shell

En ligne 3, la requête SQL récupère la colonne libelle de la table fonction. Les données sont stockées dans la variable listeFonctions. Cette variable est ensuite exploitée dans une boucle for en ligne 4.

En ligne 9, la commande mysqldump permet d’exporter une base de données vers le format SQL.

Si cela est nécessaire, les codes retour des commandes mysql et mysqldump peuvent être exploités (exemple en ligne 9).

$ nl test_sql.sh  
    1  #! /bin/bash  
 
    2  # Récupérer une liste de fonctions à partir de la BD  
    3  listeFonctions=$(mysql -unomUser -pmotPasse -h machineServeur 
--batch --skip-column-names --execute "select libelle from fonction"  
maBaseASauver 2>/dev/null)  
    4  for fonction in "$listeFonctions"   
    5  do  
    6    echo "Traitement de la fonction $fonction"  
    7  done  
 
    8  # Sauvegarde de la base de donnees  
    9  if mysqldump -unomUser -pmotPasse -h machineServeur maBaseASauver >  
/tmp/ maBaseASauver.sql 2> /tmp/erreur  
   10  then  
   11    echo "Succès sauvegarde base de données"  
   12  else  
   13    echo "Echec sauvegarde base de données"  
   14  fi 

Exécution

$ test_sql.sh  
Traitement de la fonction analyste  
Traitement de la fonction chef...