9.2. Manipuler les chaînes de caractères

Bash supporte un nombre surprenant d'opérations de manipulation de chaînes de caractères. Malheureusement, ces outils manquent d'unité. Certains sont un sous-ensemble de la substitution de paramètre et les autres font partie des fonctionnalités de la commande UNIX expr. Ceci produit une syntaxe de commande non unifiée et des fonctionnalités qui se recoupent, sans parler de la confusion engendrée.

Longueur de chaînes de caractères

${#chaine}
expr length $chaine

C'est l'équivalent de la fonction strlen() en C.

expr "$chaine" : '.*'
chaineZ=abcABC123ABCabc

echo ${#chaineZ}                 # 15
echo `expr length $chaineZ`      # 15
echo `expr "$chaineZ" : '.*'`    # 15

Exemple 9.10. Insérer une ligne blanche entre les paragraphes d'un fichier texte

&paragraphspace;

Longueur de sous-chaînes correspondant à un motif au début d'une chaîne

expr match "$chaine" '$souschaine'

$souschaine est une expression rationnelle.

expr "$chaine" : '$souschaine'

$souschaine est une expression rationnelle.

chaineZ=abcABC123ABCabc
#       |------|
#       12345678

echo `expr match "$chaineZ" 'abc[A-Z]*.2'`   # 8
echo `expr "$chaineZ" : 'abc[A-Z]*.2'`       # 8

Index

expr index $chaine $souschaine

Position numérique dans $chaine du premier caractère dans $souschaine qui correspond.

chaineZ=abcABC123ABCabc
#       123456 ...
echo `expr index "$chaineZ" C12`             # 6
                                             # C position.

echo `expr index "$chaineZ" 1c`              # 3
# 'c' (à la position #3) correspond avant '1'.

Ceci est l'équivalent le plus proche de strchr() en C.

Extraction d'une sous-chaîne

${chaine:position}

Extrait une sous-chaîne de $chaine à partir de la position $position.

Si le paramètre $chaine est « * » ou « @ », alors cela extrait les paramètres de position, [39] commençant à $position.

${chaine:position:longueur}

Extrait $longueur caractères d'une sous-chaîne de $chaine à la position $position.

chaineZ=abcABC123ABCabc
#       0123456789.....
#       indexage base 0.

echo ${chaineZ:0}                            # abcABC123ABCabc
echo ${chaineZ:1}                            # bcABC123ABCabc
echo ${chaineZ:7}                            # 23ABCabc

echo ${chaineZ:7:3}                          # 23A
                                             # Trois caractères de la sous-chaîne.



# Est-il possible d'indexer à partir de la fin de la chaîne ?

echo ${chaineZ:-4}                           # abcABC123ABCabc
# Par défaut la chaîne complète, comme dans ${parametre:-default}.
# Néanmoins...

echo ${chaineZ:(-4)}                         # Cabc
echo ${chaineZ: -4}                          # Cabc
# Maintenant, cela fonctionne.
#  Des parenthèses ou des espaces ajoutés permettent un échappement du paramètre
#+ de position.

# Merci, Dan Jacobson, pour cette indication.

Les arguments position et longueur peuvent devenir des « paramètres », c'est-à-dire représentés par une variable, plutôt que par une constante numérique.

Exemple 9.11. Générer « de manière aléatoire » une chaîne de huit caractères

&randstring;

Si le paramètre $chaine est « * » ou « @ », alors ceci extrait un maximum de $longueur du paramètre de position, en commençant à $position.

echo ${*:2}          # Affiche le deuxième paramètre de position et les suivants.
echo ${@:2}          # Identique à ci-dessus.

echo ${*:2:3}        # Affiche trois paramètres de position, en commençant par le deuxième.
expr substr $chaine $position $longueur

Extrait $longueur caractères à partir de $chaine en commençant à $position.

chaineZ=abcABC123ABCabc
#       123456789......
#       indexage base 1.

echo `expr substr $chaineZ 1 2`              # ab
echo `expr substr $chaineZ 4 3`              # ABC

expr match "$chaine" '\($souschaine\)'

Extrait $souschaine à partir du début de $chaine, et où $souschaine est une expression rationnelle.

expr "$chaine" : '\($souschaine\)'

Extrait $souschaine à partir du début de $chaine, et où $souschaine est une expression rationnelle.

chaineZ=abcABC123ABCabc
#       =======

echo `expr match "$chaineZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   # abcABC1
echo `expr "$chaineZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       # abcABC1
echo `expr "$chaineZ" : '\(.......\)'`                   # abcABC1
# Toutes les formes ci-dessus donnent un résultat identique.
expr match "$chaine" '.*\($souschaine\)'

Extrait $souschaine à la fin de $chaine, et où $souschaine est une expression rationnelle.

expr "$chaine" : '.*\($souschaine\)'

Extrait $souschaine à la fin de $chaine, et où $souschaine est une expression rationnelle.

chaineZ=abcABC123ABCabc
#                ======

echo `expr match "$chaineZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    # ABCabc
echo `expr "$chaineZ" : '.*\(......\)'`                       # ABCabc

Suppression de sous-chaînes

${chaine#souschaine}

Efface l'occurrence la plus courte de $souschaine à partir du début de $chaine.

${chaine##souschaine}

Efface l'occurrence la plus longue de $souschaine à partir du début de $chaine.

chaineZ=abcABC123ABCabc
#       |----|        la plus courte
#       |----------|  la plus longue

echo ${chaineZ#a*C}      # 123ABCabc
# Efface la plus courte occurrence entre 'a' et 'C'.

echo ${chaineZ##a*C}     # abc
# Efface la plus longue occurrence entre 'a' et 'C'.
${chaine%souschaine}

Efface la plus courte occurrence de $souschaine à partir de la fin de $chaine.

Par exemple :

# Renomme tous les fichiers de $PWD
#+ en remplaçant le suffixe "TXT" par "txt".
# Par exemple, "fichier1.TXT" devient "fichier1.txt" . . .

SUFF=TXT
suff=txt

for i in $(ls *.$SUFF)
do
  mv -f $i ${i%.$SUFF}.$suff
  #  Ne modifie rien *en dehors* de l'occurrence la plus courte
  #+ commençant du côté droit de $i . . .
done ### Ceci pourrait être condenser en une ligne si nécessaire.

# Thank you, Rory Winston.
${chaine%%souschaine}

Efface la plus longue occurrence de $souschaine à partir de la fin de $chaine.

chaineZ=abcABC123ABCabc
#                    ||   la plus courte
#        |------------|   la plus longue

echo ${chaineZ%b*c}      # abcABC123ABCa
#  Coupe la plus courte occurrence entre 'b' et 'c', à partir de la fin
#+ de $chaineZ.

echo ${chaineZ%%b*c}     # a
#  Coupe la plus courte occurrence entre 'b' et 'c', à partir de la fin
#+ de $chaineZ.

Cet opérateur est utilisé pour générer des noms de fichier.

Exemple 9.12. Convertir des formats de fichiers graphiques avec une modification du nom du fichier

&cvt;

Exemple 9.13. Convertir des fichiers audio en ogg

&ra2ogg;

Une simple émulation de getopt en utilisant des constructions d'extraction de sous-chaînes.

Exemple 9.14. Émuler getopt

&getoptsimple;

Remplacement de sous-chaîne

${chaine/souschaine/remplacement}

Remplace la première occurrence de $souschaine par $remplacement. [40]

${chaine//souschaine/remplacement}

Remplace toutes les occurrences de $souschaine par $remplacement.

chaineZ=abcABC123ABCabc

echo ${chaineZ/abc/xyz}           # xyzABC123ABCabc
                                  #  Remplace la première occurrence de
                                  #+ 'abc' par 'xyz'.

echo ${chaineZ//abc/xyz}          # xyzABC123ABCxyz
                                  #  Remplace toutes les occurrences de
                                  #+ 'abc' par 'xyz'.

echo  ---------------
echo "$chaineZ"                   # abcABC123ABCabc
echo  ---------------
# La chaîne elle-même n'est pas modifiée !

# Le motif de recherche et le remplacement peuvent-ils être
#+ paramétrisés ?

motif=abc
rempl=000
echo ${chaineZ/$motif/$rempl}  # 000ABC123ABCabc
#              ^      ^          ^^^
echo ${chaineZ//$motif/$rempl} # 000ABC123ABC000
# Oui !         ^      ^         ^^^         ^^^

echo

# Que se passe-t-il si aucune chaîne de remplacement n'est fournie ?
echo ${chaineZ/abc}           # ABC123ABCabc
echo ${chaineZ//abc}          # ABC123ABC
# On obtient une suppression pure et simple.
${chaine/#souschaine/remplacement}

Si $souschaine correspond au début de $chaine, substitue $remplacement à $souschaine.

${chaine/%souchaine/remplacement}

Si $souschaine correspond à la fin de $chaine, substitue $remplacement à $souschaine.

chaineZ=abcABC123ABCabc

echo ${chaineZ/#abc/XYZ}          # XYZABC123ABCabc
                                  #  Remplace la dernière occurrence de
                                  #+ 'abc' par 'XYZ'.

echo ${chaineZ/%abc/XYZ}          # abcABC123ABCXYZ
                                  #  Remplace la dernière occurrence de
                                  #+ 'abc' par  'XYZ'.

9.2.1. Manipuler des chaînes de caractères avec awk

Un script Bash peut utiliser des fonctionnalités de manipulation de chaînes de caractères de awk comme alternative à ses propres fonctions intégrées.

Exemple 9.15. Autres moyens pour extraire ou situer des sous-chaînes

&substringex;

9.2.2. Pour en savoir plus

Pour plus d'informations sur la manipulation des chaînes de caractères dans les scripts, voyez la Section 9.3, « Substitution de paramètres » et la section de la liste des commandes consacrée à la commande expr.

Exemples de scripts :



[39] Ceci s'applique soit aux arguments en ligne de commande soit aux paramètres passés à une fonction.

[40] Remarque : $souschaine et $remplacement peuvent se rapporter soit aux chaînes littérales, soit aux variables, suivant le contexte. Voyez le premier exemple d'utilisation.