HOWTO · Bash

Extraire la sous-chaîne en Bash

Ce didacticiel montre différentes manières d'extraire une sous-chaîne dans bash à l'aide de la commande cut, de l'expansion de la sous-chaîne et du séparateur de champ interne.

Sur cette page

Pour extraire une partie d’une chaîne dans Bash, choisissez l’opération adaptée à l’entrée : cut sélectionne un champ séparé par un délimiteur, l’expansion de sous-chaîne de Bash sélectionne des caractères selon leur position, et le découpage avec IFS transforme un texte délimité en champs que vous pouvez traiter séparément. Ces méthodes sont apparentées, mais ne renvoient pas les données de la même façon.

Extraire un champ délimité avec cut

Utilisez cut lorsque la valeur comporte un délimiteur régulier et que vous souhaitez récupérer un champ précis. L’option -d définit le délimiteur et -f sélectionne un numéro de champ, en commençant à 1. Dans cet exemple, les mots sont séparés par des traits de soulignement : le troisième champ est donc three. Placez l’expansion de variable entre guillemets et transmettez-la à printf ; la valeur reste ainsi une seule ligne d’entrée, sans recourir à la forme risquée et non protégée echo $numbers.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

numbers='one_two_three_four_five'
substring=$(printf '%s\n' "$numbers" | cut -d '_' -f 3)
printf 'substring: %s\n' "$substring"
substring: three

cut sélectionne des champs, et non une plage arbitraire de caractères. Cette méthode convient aux textes structurés dont le délimiteur et la position du champ sont connus ; si la plage recherchée dépend de positions de caractères, utilisez plutôt l’expansion de sous-chaîne.

Extraire des caractères avec l’expansion de sous-chaîne de Bash

Bash permet d’extraire une sous-chaîne sous la forme ${variable:offset:length}. Le décalage commence à zéro et la longueur indique le nombre de caractères à renvoyer. Par exemple, dans one_two_three_four_five, le décalage 4 correspond au t de two, et la longueur 3 sélectionne ces trois caractères. Tous les caractères de la chaîne d’origine, y compris les délimiteurs, comptent dans le décalage.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

numbers='one_two_three_four_five'
substring=${numbers:4:3}
printf 'substring: %s\n' "$substring"
substring: two

C’est le choix direct lorsque vous connaissez la position d’un caractère et la longueur de la plage à extraire. Le décalage n’est pas un numéro de champ : si la partie qui précède le texte recherché change de longueur, le même décalage peut sélectionner d’autres caractères. Pour une valeur séparée en champs nommés ou numérotés, cut ou IFS est généralement plus facile à adapter.

Découper une chaîne en champs avec IFS

IFS est le séparateur interne de champs de Bash. Il contrôle le découpage en mots après une expansion non protégée par des guillemets et influe aussi sur la façon dont la commande intégrée read répartit l’entrée. Une valeur temporaire de IFS permet de découper une chaîne délimitée en paramètres positionnels. $1, $2 et $3 désignent respectivement le premier, le deuxième et le troisième paramètre ; ce n’est pas la syntaxe d’indexation d’un tableau.

L’exemple limite le découpage à une fonction et désactive l’expansion des chemins avant d’utiliser l’expansion non protégée. C’est important, car l’expansion des chemins suit le découpage en mots : si un champ contient *, ? ou un motif entre crochets, le shell pourrait sinon le remplacer par les noms de fichiers correspondants. Réservez cette forme aux entrées contrôlées dont le délimiteur est connu. Si ce délimiteur n’est pas un espace blanc, définissez IFS sur ce caractère pendant que vous lisez l’entrée dans un tableau avec read -a, puis protégez les expansions du tableau par des guillemets lorsque vous utilisez les champs. Avec la valeur par défaut de IFS, les espaces, les tabulations et les retours à la ligne séparent les champs ; définir IFS sur un délimiteur fait de celui-ci le caractère de séparation. Cette méthode ne préserve pas les champs qui contiennent le délimiteur choisi, et read -a, qui traite l’entrée ligne par ligne, ne peut pas conserver les retours à la ligne intégrés à un champ. Pour ces formats, utilisez un analyseur conçu pour le format au lieu de vous fier uniquement à read -a.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

numbers='one_two_three_four_five'
extract_second() (
  local IFS=_
  set -f
  set -- $numbers
  printf 'second field: %s\n' "$2"
)
extract_second
second field: two

Dans la fonction, set -- remplace ses paramètres positionnels par les champs découpés ; à la sortie de la fonction, les paramètres positionnels de l’appelant sont rétablis. Le séparateur local ne modifie pas durablement la valeur de IFS.

Choisir la bonne méthode

Choisissez cut pour sélectionner un champ numéroté dans un texte dont le délimiteur est connu, par exemple la troisième valeur séparée par des traits de soulignement. Choisissez l’expansion de sous-chaîne de Bash pour extraire des caractères à partir d’un décalage connu, compté à partir de zéro, et sur une longueur donnée. Choisissez le découpage avec IFS lorsque les champs doivent devenir des mots shell ou des paramètres positionnels distincts afin d’être traités ensuite.

Pour une entrée prévisible, chaque option est concise. Protégez l’entrée de cut par des guillemets, utilisez des accolades pour l’expansion de sous-chaîne et gardez à l’esprit qu’une expansion non protégée utilisée pour le découpage avec IFS peut aussi déclencher l’expansion des chemins. Si le délimiteur fait partie des données ou si les champs peuvent contenir des caractères interprétés comme des motifs par le shell, privilégiez une méthode d’analyse qui conserve les champs dans des éléments de tableau protégés par des guillemets, plutôt que de vous fier au découpage non protégé en mots. Cette distinction évite de confondre un numéro de champ, un décalage de caractère et un paramètre positionnel avec différentes formes interchangeables de « sous-chaîne ».