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...