Regex Bash avancée avec des exemples
En utilisant la puissance des expressions régulières, on peut analyser et transformer des documents et des chaînes textuels. Cet article s’adresse aux utilisateurs avancés, qui sont déjà familiers avec les expressions régulières de base dans Bash. Pour une introduction aux expressions régulières Bash, consultez plutôt notre article sur les expressions régulières Bash pour les débutants avec des exemples. Un autre article qui pourrait vous intéresser est Expressions régulières en Python.
Prêt à commencer ? Plongez et apprenez à utiliser les expressions rationnelles comme un pro !
Dans ce tutoriel, vous allez apprendre :
- Comment éviter que de petites différences entre les systèmes d’exploitation n’affectent vos expressions régulières
- Comment éviter d’utiliser des modèles de recherche d’expressions régulières trop génériques comme
.* - Comment utiliser ou ne pas utiliser la syntaxe d’expression régulière étendue
- Exemples d’utilisation avancée d’expressions régulières complexes dans Bash
Regex Bash avancée avec des exemples
Configuration logicielle requise et conventions utilisées
Exemple 1 : Attention à l’utilisation d’expressions régulières étendues
Pour ce tutoriel, nous allons utiliser sed comme principal moteur de traitement d’expressions régulières. Tous les exemples donnés peuvent généralement être portés directement sur d’autres moteurs, comme les moteurs d’expressions régulières inclus dans grep, awk, etc.
Une chose à toujours garder à l’esprit lorsque vous travaillez avec des expressions régulières, c’est que certains moteurs d’expression régulière (comme celui de sed) prennent en charge la syntaxe des expressions régulières et étendues. Par exemple, sed vous permettra d’utiliser l’option -E (option abrégée pour --regexp-extended), ce qui vous permettra d’utiliser des expressions régulières étendues dans le script sed.
En pratique, cela se traduit par de petites différences dans les idiomes de syntaxe des expressions régulières lors de l’écriture de scripts d’expressions régulières. Prenons un exemple :
echo 'sample' | sed 's|[a-e]\+|_|g'
s_mpl_
echo 'sample' | sed 's|[a-e]+|_|g'
sample
echo 'sample+' | sed 's|[a-e]+|_|g'
sampl_
echo 'sample' | sed -E 's|[a-e]+|_|g'
s_mpl_
Comme vous pouvez le voir, dans notre premier exemple, nous avons utilisé \+ pour qualifier la plage a-c (remplacée globalement en raison du qualificatif g) comme nécessitant une ou plusieurs occurrences. Notez que la syntaxe, en particulier, est \+. Cependant, lorsque nous avons changé ce \+ en +, la commande a donné un résultat complètement différent. C’est parce que le + n’est pas interprété comme un caractère plus standard, ni comme une commande regex.
Cela a été prouvé par la suite par la troisième commande dans laquelle un + littéral, ainsi que le e qui le précède, a été capturé par l’expression régulière [a-e]+, et transformé en _.
En regardant en arrière que la première commande, nous pouvons maintenant voir comment le \+ a été interprété comme une expression régulière non littérale +, à traiter par sed.
Enfin, dans la dernière commande, nous indiquons à sed que nous voulons spécifiquement utiliser la syntaxe étendue en utilisant l’option de syntaxe étendue -E pour sed. Notez que le terme étendu nous donne un indice sur ce qui se passe en arrière-plan ; La syntaxe des expressions régulières est étendue pour activer diverses commandes regex, comme dans ce cas +.
Une fois que le -E est utilisé, même si nous utilisons toujours + et non \+, sed interprète correctement le + comme étant une instruction d’expression régulière.
Lorsque vous écrivez beaucoup d’expressions régulières, ces différences mineures dans l’expression de vos pensées en expressions régulières s’estompent en arrière-plan et vous aurez tendance à vous souvenir des plus importantes.
Cela souligne également la nécessité de toujours tester les expressions régulières de manière approfondie, compte tenu d’une variété d’entrées possibles, même celles auxquelles vous ne vous attendez pas.
Exemple 2 : Modification de corde à usage intensif
Pour cet exemple, et les suivants, nous avons préparé un fichier textuel. Si vous voulez vous entraîner, vous pouvez utiliser les commandes suivantes pour créer ce fichier vous-même :
echo 'abcdefghijklmnopqrstuvwxyz ABCDEFG 0123456789' > test1
cat test1
abcdefghijklmnopqrstuvwxyz ABCDEFG 0123456789
Regardons maintenant notre premier exemple de modifications de chaînes de caractères : nous aimerions que la deuxième colonne (ABCDEFG) vienne avant la première (abcdefghijklmnopqrstuvwxyz).
Pour commencer, nous faisons cette tentative fictive :
cat test1
abcdefghijklmnopqrstuvwxyz ABCDEFG 0123456789
cat test1 | sed -E 's|([a-o]+).*([A-Z]+)|\2 \1|'
G abcdefghijklmno 0123456789
Comprenez-vous cette expression régulière ? Si c’est le cas, vous êtes déjà un écrivain d’expressions régulières très avancé, et vous pouvez choisir de passer aux exemples suivants, en les parcourant pour voir si vous êtes capable de les comprendre rapidement ou si vous avez besoin d’un peu d’aide.
Ce que nous faisons ici, c’est catifier (afficher) notre fichier test1, et l’analyser avec une expression régulière étendue (grâce à l’option -E) en utilisant sed. Nous aurions pu écrire cette expression régulière en utilisant une expression régulière non étendue (dans sed) comme suit ;
cat test1 | sed 's|\([a-o]\+\).*\([A-Z]\+\)|\2 \1|'
G abcdefghijklmno 0123456789
Ce qui est exactement la même chose, sauf que nous avons ajouté un caractère \ avant chaque caractère (, ) et +, indiquant à sed que nous voulons qu’ils soient analysés comme du code d’expression régulière, et non comme des caractères normaux. Jetons maintenant un coup d’œil à l’expression régulière elle-même.
Utilisons pour cela le format d’expression régulière étendu, car il est plus facile à analyser visuellement.
s|([a-o]+).*([A-Z]+)|\2 \1|
Ici, nous utilisons la commande sed substitute (s au début de la commande), suivie d’une recherche (première |...| partie) et d’une section remplacer (deuxième |...| partie).
Dans la section de recherche, nous avons deux groupes de sélection, chacun entouré et limité par ( et ), à savoir ([a-o]+) et ([A-Z]+). Ces groupes de sélection, dans l’ordre dans lequel ils sont donnés, seront recherchés lors de la recherche dans les chaînes. Notez qu’entre les deux groupes de sélection, nous avons une expression régulière .*, ce qui signifie essentiellement n’importe quel caractère, 0 fois ou plus. Cela correspondra à notre espace entre abcdefghijklmnopqrstuvwxyz et ABCDEFG dans le fichier d’entrée, et potentiellement plus.
Dans notre premier groupe de recherche, nous recherchons au moins une occurrence de a-o suivie d’un nombre quelconque d’occurrences de a-o, indiqué par le qualificatif +. Dans le deuxième groupe de recherche, nous recherchons des lettres majuscules entre A et Z, et cela à nouveau une ou plusieurs fois dans l’ordre.
Enfin, dans notre section replace de la commande sed regular expression, nous allons rappeler/rappeler le texte sélectionné par ces groupes de recherche, et les insérer en tant que chaînes de remplacement. Notez que l’ordre est inversé ; Affichez d’abord le texte correspondant au deuxième groupe de sélection (en utilisant \2 pour indiquer le deuxième groupe de sélection), puis le texte correspondant au premier groupe de sélection (\1).
Bien que cela puisse sembler facile, le résultat à portée de main (G abcdefghijklmno 0123456789) peut ne pas être immédiatement clair. Comment avons-nous perdu ABCDEF par exemple ? Nous avons également perdu pqrstuvwxyz – l’avez-vous remarqué ?
Voici ce qui s’est passé ; Notre premier groupe de sélection a capturé le texte abcdefghijklmno. Ensuite, étant donné le .* (n’importe quel caractère, 0 fois ou plus), tous les caractères ont été mis en correspondance - et c’est important ; dans toute la mesure du possible – jusqu’à ce que nous trouvions la prochaine expression régulière correspondante applicable, le cas échéant. Puis, enfin, nous avons fait correspondre n’importe quelle lettre hors de la plage A-Z, et cette fois de plus.
Commencez-vous à comprendre pourquoi nous avons perdu ABCDEF et pqrstuvwxyz ? Bien que ce ne soit pas du tout évident, le .* a continué à correspondre aux caractères jusqu’à ce que le dernier A-Z corresponde, ce qui serait G dans la chaîne ABCDEFG.
Même si nous avons spécifié un ou plusieurs caractères (à l’aide de +) à faire correspondre, cette expression régulière particulière a été correctement interprétée par sed de gauche à droite, et sed ne s’est arrêté avec le caractère correspondant n’importe quel caractère (.*) lorsqu’il ne pouvait plus remplir la prémisse qu’il y aurait au moins un caractère majuscule de A à Z à venir.
Au total, pqrstuvwxyz ABCDEF a été remplacé par .* au lieu de simplement l’espace comme on lirait cette expression régulière dans une lecture plus naturelle, mais incorrecte. Et, comme nous ne capturons pas ce qui a été sélectionné par .*, cette sélection a simplement été supprimée de la sortie.
Notez également que toutes les parties qui ne correspondent pas à la section de recherche sont simplement copiées dans la sortie : sed n’agira que sur ce que l’expression régulière (ou la correspondance de texte) trouve.
Exemple 3 : Sélectionner tout ce qui n’est pas
L’exemple précédent nous amène également à une autre méthode intéressante, que vous utiliserez probablement pas mal si vous écrivez régulièrement des expressions régulières, et qui consiste à sélectionner du texte en faisant correspondre tout ce qui ne l’est pas. Cela semble amusant à dire, mais vous ne savez pas clairement ce que cela signifie ? Prenons un exemple :
cat test1
abcdefghijklmnopqrstuvwxyz ABCDEFG 0123456789
cat test1 | sed -E 's|[^ ]*|_|'
_ ABCDEFG 0123456789
Une expression régulière simple, mais très puissante. Ici, au lieu d’utiliser .* d’une manière ou d’une autre, nous avons utilisé [^]*. Au lieu de dire (par .*) correspondre à n’importe quel caractère, 0 fois ou plus, nous indiquons maintenant correspondre à n’importe quel caractère non espace, 0 fois ou plus.
Bien que cela semble relativement facile, vous vous rendrez vite compte du pouvoir d’écrire des expressions régulières de cette manière. Pensez par exemple à notre dernier exemple, dans lequel une grande partie du texte correspond soudainement d’une manière quelque peu inattendue. Cela pourrait être évité en changeant légèrement notre expression régulière de l’exemple précédent, comme suit :
cat test1 | sed -E 's|([a-o]+)[^A]+([A-Z]+)|\2 \1|'
ABCDEFG abcdefghijklmno 0123456789
Pas encore parfait, mais déjà mieux ; au moins, nous avons pu préserver la partie ABCDEF. Tout ce que nous avons fait, c’est changer .* en [^A]+. En d’autres termes, continuez à chercher des caractères, au moins un, à l’exception de A. Une fois que A est trouvé, cette partie de l’analyse de l’expression régulière s’arrête. A lui-même ne sera pas non plus inclus dans le match.
Exemple 4 : Revenir à notre exigence initiale
Pouvons-nous faire mieux et en effet échanger correctement la première et la deuxième colonne ?
Oui, mais pas en gardant l’expression régulière telle quelle. Après tout, il fait ce que nous lui avons demandé de faire ; faire correspondre tous les caractères de A à O à l’aide du premier groupe de recherche (et afficher plus tard à la fin de la chaîne), puis supprimer n’importe quel caractère jusqu’à ce que sed atteigne A. Nous pourrions résoudre définitivement le problème – rappelez-vous que nous voulions que seul l’espace corresponde – en étendant/changeant le a-o en a-z, ou en ajoutant simplement un autre groupe de recherche, et en faisant correspondre l’espace littéralement :
cat test1 | sed -E 's|([a-o]+)([^ ]+)[ ]([A-Z]+)|\3 \1\2|'
ABCDEFG abcdefghijklmnopqrstuvwxyz 0123456789
Génial! Mais l’expression régulière semble trop complexe maintenant. Nous avons fait correspondre a-o une ou plusieurs fois dans le premier groupe, puis n’importe quel caractère non espace (jusqu’à ce que sed trouve un espace ou la fin de la chaîne) dans le deuxième groupe, puis un espace littéral et enfin A-Z une ou plusieurs fois.
Peut-on simplifier ? Oui. Et cela devrait mettre en évidence comment on peut facilement trop compliquer les scripts d’expressions régulières.
cat test1 | sed -E 's|([^ ]+) ([^ ]+)|\2 \1|'
ABCDEFG abcdefghijklmnopqrstuvwxyz 0123456789
cat test1 | awk '{print $2" "$1" "$3}'
ABCDEFG abcdefghijklmnopqrstuvwxyz 0123456789
Les deux solutions répondent à l’exigence initiale, en utilisant des outils différents, une expression régulière beaucoup plus simplifiée pour la commande sed, et sans bogues, au moins pour les chaînes d’entrée fournies. Cela peut-il facilement mal tourner ?
cat test1
abcdefghijklmnopqrstuvwxyz ABCDEFG 0123456789
cat test1 | sed -E 's|([^ ]+) ([^ ]+)|\2 \1|'
abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFG
Oui. Tout ce que nous avons fait, c’est ajouter un espace supplémentaire dans l’entrée, et en utilisant la même expression régulière, notre sortie est maintenant complètement incorrecte ; Les deuxième et troisième colonnes ont été échangées au lieu des deux premières. Encore une fois, la nécessité de tester les expressions régulières en profondeur et avec des entrées variées est soulignée. La différence de sortie est simplement due au fait que le motif no-space space-no-space ne pouvait être correspondu qu’à la dernière partie de la chaîne d’entrée en raison du double espace.
Exemple 5 : ls gotcha ?
Parfois, un paramètre au niveau du système d’exploitation, comme par exemple l’utilisation d’une sortie couleur pour les listes de répertoires ou non (qui peut être défini par défaut !), entraînera un comportement erratique des scripts de ligne de commande. Bien qu’il ne s’agisse en aucun cas d’une faute directe des expressions régulières, c’est un piège que l’on peut rencontrer plus facilement en utilisant des expressions régulières. Prenons un exemple :
La sortie de couleur ls entache le résultat d’une commande contenant des expressions régulières
ls -d t*
test1 test2
ls -d t*2 | sed 's|2|1|'
test1
ls -d t*2 | sed 's|2|1|' | xargs ls
ls: cannot access ''
Dans cet exemple, nous avons un répertoire (test2) et un fichier (test1), tous deux listés par la commande ls -d d’origine. Ensuite, nous recherchons tous les fichiers avec un modèle de nom de fichier t*2, et supprimons le 2 du nom de fichier à l’aide de sed. Le résultat est le test de texte. Il semble que nous puissions utiliser ce test de sortie immédiatement pour une autre commande, et nous l’avons envoyé via xargs à la commande ls, en attendant que la commande ls répertorie le fichier test1.
Cependant, cela ne se produit pas, et à la place, nous obtenons une sortie très complexe à analyser humainement. La raison est simple : le répertoire d’origine était répertorié dans une couleur bleu foncé, et cette couleur est définie comme une série de codes de couleur. Lorsque vous voyez cela pour la première fois, le résultat est difficile à comprendre. La solution est cependant simple ;
ls -d --color=never t*2 | sed 's|2|1|' | xargs ls
test1
Nous avons fait en sorte que la commande ls affiche la liste sans utiliser de couleur. Cela résout complètement le problème en question et nous montre comment nous pouvons garder à l’esprit la nécessité d’éviter les petits mais significatifs paramètres spécifiques au système d’exploitation, qui peuvent interrompre notre travail d’expression régulière lorsqu’ils sont exécutés dans différents environnements, sur différents matériels ou sur différents systèmes d’exploitation.
Prêt à explorer davantage par vous-même ? Examinons quelques-unes des expressions régulières les plus courantes disponibles dans Bash :
| Expression | Description |
|---|---|
| N’importe quel caractère, à l’exception du saut de ligne |
| Un caractère de la plage sélectionnée, dans ce cas a,b,c |
| Un caractère de la plage sélectionnée, dans ce cas A-Z |
| Un caractère de l’intervalle sélectionné, dans ce cas 0-9, A et F-Z |
| Un caractère en dehors de la plage sélectionnée, dans ce cas par exemple '1' serait éligible |
| N’importe quel nombre de correspondances (0 ou plus). Utilisez * lorsque vous utilisez des expressions régulières où les expressions étendues ne sont pas activées (voir le premier exemple ci-dessus) |
| 1 ou plusieurs matchs. Idem comment comme * |
| Groupe de capture. La première fois qu’il est utilisé, le numéro de groupe est 1, etc. |
| Début de la chaîne |
| Fin de la chaîne |
| Un chiffre |
| Un non-chiffre |
| Un espace blanc |
| Un espace non blanc |
| Un caractère sur deux (une alternative à l’utilisation de []), 'a' ou 'd' |
| Échappe les caractères spéciaux, ou indique que nous voulons utiliser une expression régulière lorsque les expressions étendues ne sont pas activées (voir le premier exemple ci-dessus) |
| Caractère de retour arrière |
| Caractère de nouvelle ligne |
| Caractère de retour chariot |
| Caractère de tabulation |
Conclusion
Dans ce tutoriel, nous avons examiné en profondeur les expressions régulières Bash. Nous avons découvert la nécessité de tester longuement nos expressions régulières, avec des entrées variées. Nous avons également vu comment de petites différences de système d’exploitation, comme l’utilisation de la couleur pour les commandes ls ou non, peuvent conduire à des résultats très inattendus. Nous avons appris la nécessité d’éviter les modèles de recherche d’expressions régulières trop génériques et comment utiliser des expressions régulières étendues.
Amusez-vous à écrire des expressions régulières avancées, et laissez-nous un commentaire ci-dessous avec vos exemples les plus cool !

