Voilà la suite de ma petite introduction aux variables dans bash. Je vais traiter ici des manipulations qu'on peut faire subir aux variables avec les outils natifs de bash.
Bien mesurer sa variable.
Soit une variable VAR. Pour connaître la longueur de la chaîne représentant la valeur de VAR, on utilise cette syntaxe :
VAR=azerty echo ${#VAR} # 6
Si VAR est un tableau, alors la syntaxe précédente ne retourne que la longueur du premier élement du tableau. Pour avoir le nombre d'éléments d'un tableau il faut utiliser ceci :
VAR=( un deux trois quatre ) echo ${#VAR[@]} # 4
La longueur d'un élement du tableau s'obtient en sélectionnant l'élément visé dans la table :
echo ${#VAR[0]} # 2
Bien découper sa variable.
Si on souhaite tronquer une variable VAR à une position POS, on peut écrire ${VAR:POS} :
VAR=azerty echo ${VAR:3} # rty
On voit ici que la numérotation commence à 0 :
012345 azerty
Si on ne veut pas récupérer tout le reste de la variable, il est possible de limiter la chaîne à une longueur LON : ${VAR:POS:LON}
VAR=azertyuiop echo ${VAR:3:4} # rtyu
Parfois, on souhaite récupérer une portion déterminée à la fin d'une chaîne, sans connaître la longueur de cette dernière. On peut alors utiliser une valeur négative pour la position. Cela requière par contre de placer cette valeur entre parenthèse, ou de la faire précéder d'un espace :
VAR=un_nom_variable.20060225.txt echo "Date = ${VAR:(-12):8}" # Date = 20060225
note : si on ne "protège" pas le signe moins avec des parenthèses ou un espace, on entre en collision avec un autre élément de la syntaxe bash (voir plus bas dans cette page).
D'autres fois, on va vouloir retirer ou remplacer des bouts de chaîne dans le contenu d'une variable, sans pour autant dégainer sed et les pipes.
Il y a 4 sortes d'ablations disponibles dans la trousse à outils bash.
- Suppression du plus court morceau correspondant, en partant du début de la chaîne ${VAR#recherche} :
VAR=abcABC123ABCabc echo ${VAR#a*C} # 123ABCabc
Attention, la partie "recherche" (a*C) est semblable à une expression régulière, mais elle est très peu sophistiquée. En terme de syntaxe, c'est tout à fait comparable aux patterns "glob" que l'on peut utiliser quotidiennement avec ls par exemple :
ls [a-z][ai]* # Liste tous les élements qui commencent par une # lettre minuscule de a à z, et dont la seconde # lettre est un a ou un i. (Liste aussi les # éléments inclus dans ceux trouvés)
Contrairement aux expressions régulières plus répandues (Perl, grep, sed, ...) le caractère * ne signifie pas "zéro ou n fois le pattern précédent", mais "n'importe quel caractère".
Donc, pour tronquer une suite de "A ou B" dans une chaîne, on pourra utiliser :
VAR=ABABAB_TOTO echo ${VAR#[AB][AB][AB][AB]} # AB_TOTO
On ne pourra pas utiliser * ou {4} comme avec sed :
echo ABABAB_TOTO | sed 's,[AB]\{4\},,' # AB_TOTO echo ABABAB_TOTO | sed 's,[AB]*,,' # _TOTO
- Suppression du plus long morceau correspondant, en partant du début de la chaîne ${VAR##recherche}:
VAR=abcABC123ABCabc echo ${VAR##a*C} # abc
- Suppression du plus court morceau correspondant, en partant de la fin de la chaîne ${VAR%recherche}:
VAR=abcABC123ABCabc echo ${VAR%b*c} # abcABC123ABCa
- Suppression du plus long morceau correspondant, en partant de la fin de la chaîne ${VAR%%recherche}:
VAR=abcABC123ABCabc echo ${VAR%%b*c} # a
Bien chercher-remplacer dans sa variable.
Bash propose aussi 4 types de remplacement dans le contenu des variables.
Ces remplacements peuvent se faire sur la première occurrence trouvée, ou sur toutes les occurrences. Les syntaxes suivantes gèrent respectivement ces deux cas :
${VAR/recherche/remplacement} # première occurrence ${VAR//recherche/remplacement} # toutes les occurrences
Dans tous les cas, c'est le morceau le plus grand correspondant à "recherche" qui sera remplacé. Ainsi, on aura :
VAR=abcABC123ABCabc echo ${VAR/b*c/Z} # aZ
On peut aussi viser spécifiquement le début ou la fin d'une chaîne :
VAR=abcABC123ABCabc echo ${VAR/#abc/---} # ---ABC123ABCabc echo ${VAR/%abc/---} # abcABC123ABC---
Bien définir sa variable.
Pour les cas où les variables doivent être étroitement surveillées, on dispose de quelques outils permettant par exemple de leur donner une valeur par défaut, ou de retourner une erreur quand elles ne sont pas définies.
On sait déjà que la forme ${VAR} retourne la valeur de VAR. Mettons maintenant qu'on veuille utiliser une valeur par défaut quand la valeur de VAR n'est pas définie. On peut écrire : ${VAR-defaut}. dans ce cas, si VAR existe (nulle ou pas), on retourne sa valeur, sinon, on retourne la valeur defaut, sans changer la valeur de VAR.
Si on veut que la valeur retournée soit non nulle, on peut utiliser la syntaxe : ${VAR:-defaut}.
Par exemple :
declare VAR # VAR existe, mais est nulle echo ${VAR-valeur_par_defaut} # rien echo ${VAR:-valeur_par_defaut} # valeur_par_defaut unset VAR # VAR n'est plus définie echo ${VAR-valeur_par_defaut} # valeur_par_defaut echo ${VAR:-valeur_par_defaut} # valeur_par_defaut
Donc, si null est une valeur possible pour une variable, il convient d'utiliser la syntaxe ${VAR-defaut} qui respectera la valeur nulle. Sinon, il est plus sage d'utiliser ${VAR:-defaut}.
Il faut bien ce souvenir que cette syntaxe ne défini à aucun moment la valeur de VAR. C'est le rôle de la syntaxe ci dessous de définir VAR si elle n'est pas définie :
declare VAR # VAR existe, mais est nulle echo ${VAR=valeur_par_defaut} # rien, VAR reste nulle echo ${VAR:=valeur_par_defaut} # VAR prend la valeur # valeur_par_defaut
Si on veut maintenant utiliser une autre valeur, fixe, quand VAR est définie, sans pour autant modifier la valeur réelle de VAR, on peut procéder comme cela :
VAR=valeur_1 echo ${VAR+autre_valeur} # autre_valeur VAR= # null echo ${VAR+autre_valeur} # autre_valeur echo ${VAR:+autre_valeur} # rien
Dernier cas maintenant : on veut utiliser la valeur de VAR, mais on veut retourner un message d'erreur si la valeur est nulle ou si VAR n'est pas définie. On peut alors procéder comme cela :
unset VAR # VAR n'est pas définie echo ${VAR?pas definie} # -bash: VAR: pas definie (sur stderr) VAR= # définie mais vide, null echo ${VAR?pas definie} # rien, valeur nulle autorisée echo ${VAR:?valeur nulle} # -bash: VAR: pas definie (sur stderr)
Bon, j'ai conscience que cela est plutôt indigeste, n'hésitez pas à poser vos questions et faire part de vos remarques.
Pour aller un peu plus loin, n'hésitez pas à consulter les autres articles sur bash !
Excellent,
merci.
Merci pour cet article. super !
PS : Il y a une petite coquille pour ${VAR%%recherche} je pense ;-)
Suppression du plus court (long) morceau correspondant, en partant de la fin de la chaîne
Merci, c'est corrigé !