Manipulations sur les variables dans Bash

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 !

À lire aussi :

3 comments

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

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.