103.7 Leçon 1
Certification : |
LPIC-1 |
---|---|
Version : |
5.0 |
Thème : |
103 Commandes GNU et Unix |
Objectif : |
103.7 Recherche dans des fichiers texte avec les expressions régulières |
Leçon : |
1 sur 2 |
Introduction
Les algorithmes de recherche de chaînes de caractères sont couramment utilisés dans le traitement de données, si bien que les systèmes d’exploitation de type Unix disposent de leur propre implémentation généralisée : les expressions régulières, souvent abrégées en regex. Les expressions régulières sont des séquences de caractères qui constituent un motif générique utilisé pour localiser et parfois modifier une séquence correspondante dans une chaîne de caractères plus volumineuse. Les expressions régulières permettent notamment de :
-
Écrire des règles d’analyse pour les requêtes dans les serveurs HTTP comme nginx.
-
Écrire des scripts qui convertissent des jeux de données texte vers un autre format.
-
Rechercher des occurrences pertinentes dans les fichiers de journalisation (logs) ou les documents.
-
Filtrer les documents balisés en conservant le contenu sémantique.
L’expression régulière la plus simple contient au moins un atome. Un atome, ainsi nommé parce qu’il est l’élément de base d’une expression régulière, n’est qu’un caractère qui peut ou ne peut pas avoir une signification particulière. La plupart des caractères ordinaires ne sont pas ambigus, ils conservent leur sens littéral, tandis que d’autres ont une signification particulière :
.
(point)-
L’atome correspond à n’importe quel caractère.
^
(accent circonflexe)-
L’atome correspond au début d’une ligne.
$
(signe dollar)-
L’atome correspond à la fin d’une ligne.
Par exemple, l’expression régulière bc
composée des atomes littéraux b
et c
peut être trouvée dans la chaîne abcd
, mais ne peut pas être trouvée dans la chaîne a1cd
. D’un autre côté, l’expression régulière .c
peut être trouvée dans les deux chaînes abcd
et a1cd
, étant donné que le point .
correspond à n’importe quel caractère.
Les atomes ^
(accent circonflexe) et $
(signe dollar) sont utilisés lorsque seules les correspondances au début ou à la fin de la chaîne de caractères sont pertinentes. C’est pour cela qu’on les appelle également ancres. Par exemple, cd
peut être trouvé dans abcd
, mais pas ^cd
. De même, ab
peut être trouvé dans abcd
, mais pas ab$
. L’accent circonflexe ^
est un caractère littéral sauf au début, et le signe dollar $
est un caractère littéral sauf à la fin de l’expression régulière.
L’expression entre crochets
Il existe un autre type d’atome appelé expression entre crochets. Même s’ils ne constituent pas un seul caractère, les crochets []
(avec leur contenu) sont considérés comme un seul atome. Une expression entre crochets n’est généralement qu’une liste de caractères littéraux entourés de []
, ce qui permet à l’atome de correspondre à n’importe quel caractère de la liste. Par exemple, l’expression [1b]
peut être trouvée dans les deux chaînes abcd
et a1cd
. Pour spécifier les caractères auxquels l’atome ne doit pas correspondre, la liste doit commencer par ^
, comme dans [^1b]
. Il est également possible de spécifier des plages de caractères dans des expressions entre crochets. Par exemple, [0-9]
correspond aux chiffres de 0 à 9 et [a-z]
à toute lettre minuscule. Les plages doivent être utilisées avec précaution, car elles peuvent ne pas être cohérentes selon les différents paramètres régionaux.
Les listes d’expressions entre crochets acceptent également des classes en remplacement des caractères simples et des plages de caractères. Voici les classes de caractères traditionnelles :
[:alnum:]
-
Représente un caractère alphanumérique.
[:alpha:]
-
Représente un caractère alphabétique.
[:ascii:]
-
Représente un caractère qui fait partie du jeu de caractères ASCII.
[:blank:]
-
Représente un caractère d’espacement, c’est-à-dire une espace ou une tabulation.
[:cntrl:]
-
Représente un caractère de contrôle.
[:digit:]
-
Représente un chiffre (0 à 9).
[:graph:]
-
Représente n’importe quel caractère imprimable sauf l’espace.
[:lower:]
-
Représente un caractère minuscule.
[:print:]
-
Représente n’importe quel caractère imprimable y compris l’espace.
[:punct:]
-
Représente n’importe quel caractère imprimable qui n’est pas une espace ou un caractère alphanumérique.
[:space:]
-
Représente les caractères d’espacement : espace, saut de page (
\f
), saut de ligne (\n
), retour chariot (\r
), tabulation horizontale (\t
) et tabulation verticale (\v
). [:upper:]
-
Représente une lettre majuscule.
[:xdigit:]
-
Représente les chiffres hexadécimaux (0 à F).
Les classes de caractères peuvent être combinées avec des caractères simples et des plages. En revanche, elles ne peuvent pas être utilisées comme élément final d’une plage. Par ailleurs, les classes de caractères ne peuvent être utilisées que dans des expressions entre crochets, et non en tant qu’atome indépendant en dehors des crochets.
Les quantificateurs
La portée d’un atome, qu’il s’agisse d’un atome à un seul caractère ou d’un atome entre crochets, peut être ajustée par le biais d’un quantificateur atomique. Les quantificateurs atomiques définissent des séquences d’atomes, c’est-à-dire que les correspondances ont lieu lorsqu’une répétition contiguë de l’atome a été trouvée dans la chaîne de caractères. La sous-chaîne de caractères associée à la correspondance est appelée une pièce. Cela dit, les quantificateurs et d’autres fonctionnalités des expressions régulières sont traités différemment en fonction de la norme utilisée.
D’après la norme POSIX, il existe deux formes d’expressions régulières : les expressions régulières "basiques" et "étendues". La plupart des programmes de traitement de texte installés dans une distribution Linux conventionnelle prennent en charge les deux formes. Il est donc important de connaître leurs différences afin d’éviter les problèmes de compatibilité et de choisir l’implémentation la plus adaptée à la tâche envisagée.
Le quantificateur *
a la même fonction dans les expressions régulières basiques et étendues (l’atome apparaît zéro fois ou plus) et c’est un caractère littéral s’il apparaît au début de l’expression régulière ou s’il est précédé d’une barre oblique inverse \
. Le quantificateur plus ` sélectionnera les éléments contenant une ou plusieurs correspondances d'atomes dans l'ordre. Avec le quantificateur point d'interrogation `?`, une correspondance sera obtenue si l'atome correspondant apparaît une fois ou pas du tout. S'ils sont précédés d'une barre oblique inverse `\`, leur signification particulière n'est pas prise en compte. Les expressions régulières basiques supportent également les quantificateurs `
et ?
, mais ils doivent être précédés d’une barre oblique inverse. Contrairement aux expressions régulières étendues, +
et ?
sont des caractères littéraux dans les expressions régulières basiques.
Les limites
Une limite est un quantificateur atomique qui, comme son nom l’indique, permet à l’utilisateur de spécifier des limites quantitatives précises pour un atome. Dans les expressions régulières étendues, une limite peut apparaître sous trois formes :
{i}
-
L’atome doit apparaître exactement
i
fois (i
étant un nombre entier). Par exemple,[[:blank:]]{2}
correspond exactement à deux caractères vides. {i,}
-
L’atome doit apparaître au moins
i
fois (i
étant un nombre entier). Par exemple,[[:blank:]]{2,}
correspond à toute séquence d’au moins deux caractères vides. {i,j}
-
L’atome doit apparaître au minimum
i
et au maximumj
fois (i
etj
étant des nombres entiers, avecj
supérieur ài
). Par exemple,xyz{2,4}
correspond à la chaînexy
suivie de deux à quatre fois le caractèrez
.
Dans tous les cas, si une sous-chaîne correspond à une expression régulière et qu’une sous-chaîne plus longue et qui commence au même endroit correspond également, la sous-chaîne la plus longue sera prise en compte.
Les expressions régulières basiques autorisent également les limites, mais les délimiteurs doivent être précédés de \
: \{
et \}
. En eux-mêmes, {
et }
sont interprétés comme des caractères littéraux. Un \{
suivi d’un caractère autre qu’un chiffre est un caractère littéral, et non pas le début d’une délimitation.
Les branches et les renvois
Les expressions régulières basiques se distinguent également des expressions régulières étendues par un autre aspect important : une expression régulière étendue peut être subdivisée en branches, chacune d’entre elles étant une expression régulière indépendante. Les branches sont séparées par des |
et l’expression régulière combinée s’appliquera à tout ce qui correspond à l’une des branches. Par exemple, he|him
s’appliquera si les sous-chaînes he
ou him
figurent dans la chaîne de caractères analysée. Les expressions régulières basiques interprètent |
comme un caractère littéral. En revanche, la plupart des programmes prenant en charge les expressions régulières basiques autorisent les branches avec \|
.
Une expression régulière étendue entourée de ()
peut être utilisée dans un renvoi vers une référence. Par exemple, ([[:digit:]])\1
correspondra à toute expression régulière qui se répète au moins une fois, parce que le \1
dans l’expression est le renvoi vers la pièce correspondant à la première sous-expression entre parenthèses. Si plusieurs sous-expressions entre parenthèses existent dans l’expression régulière, elles pourront être référencées par \2
, \3
et ainsi de suite.
Pour les regex basiques, les sous-expressions doivent être entourées de \(
et \)
, les (
et )
étant eux-mêmes des caractères ordinaires. L’indicateur de renvoi est utilisé comme dans les expressions régulières étendues.
Recherche à l’aide d’expressions régulières
L’avantage le plus immédiat des expressions régulières consiste à améliorer les recherches dans les systèmes de fichiers et dans les documents texte. L’option -regex
de la commande find
permet de tester chaque chemin dans une hiérarchie de répertoires en fonction d’une expression régulière. Par exemple,
$ find $HOME -regex '.*/\..*' -size +100M
recherche les fichiers de plus de 100 mégaoctets (100 unités de 1048576 octets), mais uniquement dans les chemins du répertoire personnel de l’utilisateur qui contiennent une correspondance avec .*/\..*
, c’est-à-dire un /.
entouré de n’importe quel autre nombre de caractères. En d’autres termes, seuls les fichiers cachés ou les fichiers situés dans des répertoires cachés seront affichés, quelle que soit la position de /.
dans le chemin d’accès correspondant. Pour des expressions régulières insensibles à la casse, l’option -iregex
devra être utilisée à la place :
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
Dans cet exemple, l’expression régulière contient des branches (écrites dans le style étendu) pour afficher certains fichiers de polices dans l’arborescence /usr/share/fonts
. Les expressions régulières étendues ne sont pas supportées par défaut, mais find
permet de les activer avec -regextype posix-extended
ou -regextype egrep
. Le standard regex par défaut pour find
est findutils-default, qui est virtuellement un clone d’expression régulière basique.
Il est souvent nécessaire de transmettre le résultat d’un programme à la commande less
lorsqu’il ne tient pas sur l’écran. La commande less
fractionne son entrée en pages, une page d’écran à la fois, ce qui permet à l’utilisateur de naviguer facilement dans le texte vers le haut et vers le bas. De plus, less
permet à l’utilisateur d’effectuer des recherches basées sur les expressions régulières. Cette fonctionnalité est particulièrement importante car less
est le paginateur par défaut utilisé pour de nombreuses tâches quotidiennes, comme l’inspection d’entrées de journal ou la consultation de pages de manuel. Lors de la lecture d’une page de manuel, par exemple, la touche / ouvre une invite de recherche. Il s’agit d’un scénario typique dans lequel les expressions régulières sont utiles, car les options de commande sont affichées juste après une marge dans la mise en page générale du manuel. Cependant, la même option peut apparaître plusieurs fois dans le texte, ce qui rend les recherches littérales impossibles. Quoi qu’il en soit, en tapant ^[[:blank:]]*-o
— ou plus simplement : ^ *-o
— à l’invite de recherche, on passe immédiatement à la section de l’option -o
(si elle existe) après avoir appuyé sur Entrée, ce qui permet de consulter plus rapidement la description d’une option.
Exercices guidés
-
Quelle expression régulière étendue correspondrait à n’importe quelle adresse électronique, comme
info@example.org
? -
Quelle expression régulière étendue correspondrait uniquement à une adresse IPv4 au format standard de type quartet pointillé, comme
192.168.15.1
? -
Comment la commande
grep
peut-elle être utilisée pour lister le contenu du fichier/etc/services
, en ignorant tous les commentaires (lignes commençant par#
) ? -
Le fichier
domains.txt
contient une liste de noms de domaines, un par ligne. Comment utiliser la commandeegrep
pour lister les seuls domaines.org
ou.com
?
Exercices d’approfondissement
-
Depuis le répertoire courant, comment la commande
find
utiliserait-elle une expression régulière étendue pour rechercher tous les fichiers qui ne contiennent pas un suffixe de fichier standard (noms de fichiers ne se terminant pas par.txt
ou.c
, par exemple) ? -
La commande
less
est le programme de pagination par défaut pour l’affichage de fichiers texte longs dans le shell. En tapant/
, une expression régulière peut être saisie dans l’invite de recherche pour aller au premier résultat correspondant. Quelle combinaison de touches doit être saisie à l’invite de recherche pour rester dans la position actuelle du document et seulement mettre en surbrillance les correspondances ? -
Dans
less
, comment serait-il possible de filtrer le résultat de sorte que seules les lignes qui correspondent à une expression régulière s’affichent ?
Résumé
Cette leçon aborde la prise en charge générale par Linux des expressions régulières, une norme largement utilisée dont les fonctionnalités de recherche de motifs sont supportées par la plupart des programmes de traitement de texte. La leçon comprend les étapes suivantes :
-
Qu’est-ce qu’une expression régulière.
-
Les principaux composants d’une expression régulière.
-
Les différences entre les expressions régulières basiques et étendues.
-
Comment effectuer des recherches de texte et de fichiers simples à l’aide des expressions régulières.
Réponses aux exercices guidés
-
Quelle expression régulière étendue correspondrait à n’importe quelle adresse électronique, comme
info@example.org
?egrep "\S+@\S+\.\S+"
-
Quelle expression régulière étendue correspondrait uniquement à une adresse IPv4 au format standard de type quartet pointillé, comme
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
Comment la commande
grep
peut-elle être utilisée pour lister le contenu du fichier/etc/services
, en ignorant tous les commentaires (lignes commençant par#
) ?grep -v ^# /etc/services
-
Le fichier
domains.txt
contient une liste de noms de domaines, un par ligne. Comment utiliser la commandeegrep
pour lister les seuls domaines.org
ou.com
?egrep ".org$|.com$" domains.txt
Réponses aux exercices d’approfondissement
-
Depuis le répertoire courant, comment la commande
find
utiliserait-elle une expression régulière étendue pour rechercher tous les fichiers qui ne contiennent pas un suffixe de fichier standard (noms de fichiers ne se terminant pas par.txt
ou.c
, par exemple) ?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
La commande
less
est le programme de pagination par défaut pour l’affichage de fichiers texte longs dans le shell. En tapant/
, une expression régulière peut être saisie dans l’invite de recherche pour aller au premier résultat correspondant. Quelle combinaison de touches doit être saisie à l’invite de recherche pour rester dans la position actuelle du document et seulement mettre en surbrillance les correspondances ?Appuyer sur Ctrl+K avant de saisir le terme de la recherche.
-
Dans
less
, comment serait-il possible de filtrer le résultat de sorte que seules les lignes qui correspondent à une expression régulière s’affichent ?En appuyant sur & et en saisissant l’expression recherchée.