Vous n'êtes pas identifié(e).
L'icône rouge permet de télécharger chaque page du wiki visitée au format PDF et la grise au format ODT →
Ceci est une ancienne révision du document !
NOTA
Il s'agira de distinguer ERb et ERe et de savoir les utiliser en fonction des commandes qui les utilisent pour effectuer des recherches de fichiers, des recherches dans le contenu des fichiers, et pour les commandes d'édition, des modifications (ajout, suppression dans le contenu) de fichiers.
Pour apprendre à utiliser les expressions rationnelles, il faut en passer par l'exercice.
Mais pour être en mesure d'en passer par l'exercice, il faut nécessairement en passer par les programmes utilisant les expressions rationnelles. C'est là que les choses se compliquent pour le néophyte.
Il faut savoir en effet que :
Heureusement, pour s'éviter d'assimiler en même temps tous ces différents types, il est possible sous GNU/Linux, d'utiliser avec chacun des programmes spécifiques à la gestion des fichiers, soit par défaut, soit au moyen d'une option, les expressions rationnelles basiques (ERb) et/ou les expressions rationnelles étendues (ERe).
Heureusement encore, les ERb et ERe donnent un très bon aperçu de ce que permettent les ER ; et ils sont de plus POSIX, c'est-à-dire portables.
Le contexte de cet apprentissage, se limitera donc à l'utilisation des expressions rationnelles au moyen des commandes de gestion des fichiers, et appréhendera seulement les expressions rationnelles POSIX qui reposent sur la bibliothèque regex, et qui s'utilisent en ligne de commandes ou dans des scripts shell.
On peut aussi combiner, par exemple, find et grep permettent de rechercher une chaîne et le fichier contenant cette chaîne en une ligne de commande avec un pipe. Mais, concernant tous ces programmes, je me limiterai strictement à leur utilisation relativement aux ER.
Dans un premier temps, je donnerai la liste des caractères ERb et ERe, puis je montrerai comment les utiliser avec chacun de ces programmes.
Les métacaractères du shell (ou joker) | |
* | n'importe quelle chaîne de n'importe quels caractères |
? | un caractère quelconque et un seul |
les “bracket expression” | |
[ ] | un caractère cité dans la liste entre crochets |
[ - ] | groupe de caractères |
ls *
milou test titi titi1 titi.txt toto Toto1.txt tata tintin titi. titi1.txt tito toto. Toto.txt
ls titi?
titi. titi1
ls [Tt][io]t[io]?
titi. titi1 toto.
ls t[a-z]t[a-z]
tata titi tito toto
Il en serait de même avec les commandes echo et rm par exemple.
Les commandes de recherche de fichier, grep, find et locate, utilisent les ER mais aussi les métacaractères du shell, dont certains caractères sont homonymes à ceux des ER.
Si certains métacaractères sont identiques aux caractères des ER leur signification n'est pas la même.
Afin d'éviter toute confusion, voyons comment et dans quel contexte ces commandes utilisent les métacaractères du shell.
Imaginons qu'on cherche tous les fichiers comportant le caractère “e”.
grep -lR "e" Toto*
option -l : Ne pas afficher les résultats normaux. À la place, indiquer le nom des fichiers pour lesquels des résultats auraient été affichés.
option -R : Lire récursivement tous les fichiers à l'intérieur de chaque répertoire.
Toto.txt
grep -lR "e" titi?
titi. titi1
grep -lR "e" [Tt][io]t[io]?
titi. titi1
find ~/ERetCMD/Dossier/ -name "toto*"
/home/hypathie/ERetCMD/Dossier/toto /home/hypathie/ERetCMD/Dossier/toto.
find ~/ERetCMD/Dossier/ -name "titi?"
/home/hypathie/ERetCMD/Dossier/titi1 /home/hypathie/ERetCMD/Dossier/titi.
find ~/ERetCMD/Dossier/ -name "[Tt][io]t[io]?"
/home/hypathie/ERetCMD/Dossier/titi1 /home/hypathie/ERetCMD/Dossier/toto. /home/hypathie/ERetCMD/Dossier/titi.
# updatedb
pour effectuer les mises à jour, avant de lancer la recherche.
ls ~/ERetCMD/
Dossier liste1-nom~ server-0.xkb sort2.txt essai.grep2~ liste2-nom smolski-exo-sed.txt sort3.txt liste1-nom liste3-erb-ere sort1.txt xxx-sort.txt
Depuis n'importe où dans l'arborescence de fichiers :
locate ~/ERetCMD/*.txt
/home/hypathie/ERetCMD/smolski-exo-sed.txt /home/hypathie/ERetCMD/sort1.txt /home/hypathie/ERetCMD/sort2.txt /home/hypathie/ERetCMD/sort3.txt /home/hypathie/ERetCMD/xxx-sort.txt
Puisque tout est bien clair, nous pouvons aller plus loin
Certains caractères sont communs au ERb et ERe, pour ne pas avoir à les répéter, il est préférable de les regrouper. D'autant plus que les commandes qui permettent de se servir des ER en général, reconnaissent tous les caractères communs aux ERb et ERe, excepté pour les classes.
expressions | Modèles reconnus |
---|---|
c | Tout non métacaractère c. |
\ | Échappement du caractère spécial. Par exemple \. sélectionne un point littéral. |
^ | Test effectué au début de la chaîne. |
$ | Test effectué à la fin de la chaîne. |
. | Tout caractère sauf une fin de ligne. |
* | Zéro à n chaînes consécutives validées par l’expression régulière r. |
\< | début d'un mot (caractères pouvant faire partie de [A-Z-z0-9] |
\> | Fin d'un mot |
[liste_de_caractères] | Un caractère cité dans la liste |
[^liste_de_caractères] | Un carcatère qui n'est pas dans la liste |
1 2 Francine 2 3 Édith 3 4 Géraldine 123 AAAAAA tout le monde partout toutefois 4 5 Béatrice 5 6 Christelle 5 7 Dorothée 6 8 Amanda
La dernière ligne du fichier est vide.
grep "^4" liste1-nom
4 5 Béatrice
grep "e$" liste1-nom
1 2 Francine 3 4 Géraldine 4 5 Béatrice 5 6 Christelle 5 7 Dorothée
grep "^$" liste1-nom
grep ".dith" liste1-nom
2 3 Édith
grep "A*" liste1-nom
1 2 Francine 2 3 Édith 3 4 Géraldine 123 AAAAAA tout le monde partout toutefois 4 5 Béatrice 5 6 Christelle 5 7 Dorothée 6 8 Amanda
Attention, il ne s'agit pas du métaractère. Étoile signifie “zéro ou plusieurs 'A'” ; zéro fois aussi, donc toutes les lignes dépourvues du caractère “A” apparaissent aussi, y compris la ligne vide.
grep "123 A*" liste1-nom
123 AAAAAA
grep "[43]" liste1-nom
2 3 Édith 3 4 Géraldine 123 AAAAAA 4 5 Béatrice
les lignes comportant 4 ou 3
Chaîne qui commence ni par 1, ni par 2, ni par aucun des caractères entre crochets.
grep "^[^12345678]" liste1-nom
tout le monde partout toutefois
grep "[^e]$" liste1-nom
2 3 Édith 123 AAAAAA partout toutefois 6 8 Amanda
grep "[^a-z]$" liste1-nom
123 AAAAAA
grep "\<tout" liste1-nom
tout le monde toutefois
grep "fois\>" liste1-nom
toutefois
grep "\<tout\>" liste1-nom
tout le monde
-regex motif
: Nom de fichier correspondant à l'expression rationnelle 'motif'.-iregex motif
: Semblable à -regex, mais sans différencier les majuscules et les
Je ne donnerai que quelques exemples, puisque tous les caractères de ERb sont utilisables.
Je m'attacherai surtout à la syntaxe de find pour ce faire.
ls
Dossier liste1-nom~ server-0.xkb sort2.txt essai.grep2~ liste2-nom smolski-exo-sed.txt sort3.txt liste1-nom liste3-erb-ere sort1.txt xxx-sort.txt
find -regextype "posix-basic" -regex ".*/li.*m"
./liste2-nom ./liste1-nom
Le premier groupe de.*
décrit le chemin du ou des fichiers dont le nom correspond à une chaîne commençant par “li” suivi de plusieurs caractères puis un “m”.
Attention la même commande lancée depuis le répertoire personnel de l'utilisateur par exemple et non depuis le répertoire parent des fichiers :
find -regextype "posix-basic" -regex ".*/li.*m"
./ERetCMD/liste2-nom ./ERetCMD/liste1-nom ./.config/libreoffice/3/user/gallery/sg100.thm ./.config/libreoffice/3/user/gallery/sg30.thm
fichiers comportant un “e” ou un “s”, plusieurs caractères, un point littéral (\.), plusieurs caractères :
find -regextype "posix-basic" -regex ".*/[es].*\..*"
./smolski-exo-sed.txt ./server-0.xkb ./sort3.txt ./sort1.txt ./essai.grep2~ ./sort2.txt
--regex
Sinon, locate reconnaît le caractère *
comme un métacaractère du shell.
Contrairement à find, il n'est pas nécessaire que la ER corresponde au chemin absolu d'un fichier.
Mais la quantité de réponses peut être très élevée, si on a une idée du répertoire dans lequel se trouve le fichier recherché, il peut plus confortable de le préciser.
On peut aussi filtrer le retour avec grep.
Néanmoins, l'utilisation des ERe règle ce problème. (Voir plus bas)
Enfin, avec l'utilisation de locate, on n'aura guère l'occasion d'utiliser les caractères début (^) et fin de ligne ($).
En effet, avec une commande qui cherche des noms de fichiers en fonction d'une chaîne contenu dans ce nom, on ne peut utiliser que '^/'
, c'est-à-dire, le début du chemin absolu, ce qui demande d'allonger inutilement l'expression régulière !
locate --regexp '/home.*[Tt]o.*'
Donne un retour de plusieurs pages par exemple en cas d'une grande quantité de photo dans un des répertoires de l'utilisateur.
locate --regexp '/home.*[Tt]o.*' | grep "/Dossier/"
/home/hypathie/ERetCMD/Dossier/Toto.txt /home/hypathie/ERetCMD/Dossier/Toto1.txt /home/hypathie/ERetCMD/Dossier/tito /home/hypathie/ERetCMD/Dossier/toto /home/hypathie/ERetCMD/Dossier/toto.
\<
:locate --regexp '.*\<smolski.*'
/home/hypathie/ERetCMD/smolski-exo-sed.txt
Pour les caractères considérés ci-dessus, . ; *, ^, $, [liste de caractères], [^liste de caractères], \<, \>
,
il en va de même pour la commande sed que pour la commande grep.
Je ne donnerai que quelques exemples.
Il est à noter que sans l'option -i, les exemples ne modifieront pas le fichier.
Comme grep pour les caractères vues jusqu'ici :
Par exemple, supprimer la ligne vide :
sed '/^$/ d' liste1-nom
Par exemple, substituer “AAAAAA” par abc
sed '/A*/s/AAAAAA/COUCOU/' liste1-nom
1 2 Francine 2 3 Édith 3 4 Géraldine 123 COUCOU tout le monde partout toutefois 4 5 Béatrice 5 6 Christelle 5 7 Dorothée 6 8 Amanda
Par exemple, tout supprimer sauf (!
)2) la ligne correspondant à un mot finissant par “fois”
sed '/fois\>/ !d' liste1-nom
toutefois
Si la signification des caractère est la même, l'action de la commande modifie “la phrase”, ou le sens global de la ER.
Comparer l'usage des [^ ] de grep avec ce qui suit :
echo "12 f 6 7" | sed 's/^[^12345678]/coucou/g'
12 f 6 7
Il ne se passe rien car avec sed la signification de la ER est : “substitue le caractère de début de la ligne qui ne commence pas par l'un des caractères '1234567'”.
sed ne cherche pas comme grep une chaîne ou un cataère qui “ne commence pas par l'un des caractères '1234567'”, et ne substituerait pas “f” de cette manière.
Ainsi :
echo " 12 f 6 7" | sed 's/[^1-7]/X/g'
X12XXX6X7
Le sens de la ER est “substitue tout ce qui n'est pas 1, 2, 3, 4, 5, 6, 7 par “X”
Y compris les espaces !
Il ne faut donc pas s'imaginer que sed utilise une version non posix des ER, telle que la littérature à son sujet l'alimente parfois.
Ce n'est que pour ce qui concerne les implantations GNU qui ne sont pas posix, que sed présente quelques bizarreries.
Rien d'obscure et pas d'obscurantisme, tout reste logique, à condition de savoir en changer… C'est là ce qui rend passionnant l'utilisation d'un méta-langage, la possibilité de la différence par delà l'identité des éléments, au moyen du contexte !
La commande awk travail sur les colonnes, les lignes, les mots, et constitue un langage de programmation. Je ne rappellerai pas toutes les fonctions de awk mais présenterai seulement comment utiliser les ER pour une utilisation basique de cette commande.
L'usage le plus simple d'awk consiste à utiliser une ER pour sélectionner une chaîne.
Le contenu des champs sont enregistrés dans les variables $1, $2, $3, …, correspondant aux colonnes 1, 2, 3, …
Avec awk la ER est encadrée par des slash /ER/
.
echo "123 AAAAAA" | awk '/A*/{print $2}'
AAAAAA
Notez qu'il s'agit bien du caractère*
qui signifie “une ou plusieurs fois 'A', et non du métacaratère*
.
Notez encore que cet exemple est un peu surfait. Il ne sert qu'à vérifier si la ER est juste, et à rappeler la syntaxe d'utilisation d'une ER avec awk. C'est que awk ne sert pas à vérifier l'exactitude d'une ER. Au contraire la ER sert de condition (correspondance de la chaîne AAAAAA avecA*
) pour effectuer une action (ici imprimer, c'est-à-dire afficher la colonne n°2).
Néanmoins, cet exemple permet d'insister encore une fois : il est important de bien comprendre que la signification globale d'une ER dépend du contexte créé par les commandes.
Modifions l'exemple ci-dessus, afin de comparer l'utilisation d'une ER dans le contexte de awk avec celui de sed.
echo " 12 f 6 7" | sed 's/[^1-7]/X/g'
X12XXX6X7
substitution par “X” de tout ce qui n'est pas 1, 2, 3, 4, 5, 6, 7
echo "12 f 6 7" | awk '/[^12345678]/{print $2}'
f
Afficher le champ n°2 ($2
) si la ER ( “tout ce qui n'est pas 1, 2, 3, 4, 5, 6, 7”) est vraie.
Chaque commande crée un contexte différents qui détermine l'usage des ER.
Si l'utilisation des ER est souvent déprécié, c'est pour une bonne part parce que leurs différents contextes ne sont jamais mis en confrontation.
Mais une fois ces contextes précisés, et une fois s'être exercé à passer de l'un à l'autre, l'utilisation des ER devient bien plus facile.
cat liste1-nom
1 2 Francine 2 3 Édith 3 4 Géraldine 123 AAAAAA tout le monde partout toutefois 4 5 Béatrice 5 6 Christelle 5 7 Dorothée 6 8 Amanda
awk '$1 ~ /^4/' liste1-nom
Affiche la ligne ou les lignes dont la colonne n°1 correspond à la ER (“qui commence par 4”).
4 5 Béatrice
L'action par défaut est print, s'il aucune action n'est mentionnée et que la condition est vraie.
~
est un opérateur de correspondance entre une ER et une variable.<
; >
; ==
…
awk '$3 ~ /ce$/' liste1-nom
4 5 Béatrice
awk '$3 ~ /.d.*/' liste1-nom
Affiche la ou les lignes dont le troisième champ (colonne) comporte une chaîne correspondant à “un caractère (.
), suivi d'und
, suivi d'un ou plusieurs caractères (.*
).
2 3 Édith 3 4 Géraldine tout le monde 6 8 Amanda
awk '$3 ~/t[h]/' liste1-nom
Affiche la ou les lignes dont la chaîne correspond à la ER “t” ou “th”
2 3 Édith 5 7 Dorothée
awk '$1 ~ /^[^12345678]/' liste1-nom
tout le monde partout toutefois
!~
propre à awk :awk '$1 !~ /^[12345678]/' liste1-nom
tout le monde partout toutefois
La seule différence entre$1 ~ /^[^12345678]/
et$1 !~ /^[12345678]/
, c'est que la deuxième ER affichera une ligne vide, et non la première.
awk '$1 ~ /fois\>/' liste1-nom
toutefois
expressions | Modèles reconnus |
---|---|
\{m\} | m fois le caractère précédent |
\{m,\} | au moins m fois le caractère précédent |
\{m,n\} | entre m et n fois le caractère précédent |
\(ERb\) | mémorisation d'une ERb |
\1, \2, ... | Rappel de mémorisation |
→ Le caractère \
donne une signification spéciale aux parenthèses et accolades, au lieu de les rendre littérales.
Soit le fichier “liste4-spec” :
cat liste4-spec
gdd:a:aa:aaa:aaaa:aaaaaa:aaaaaaaa T5c Kc5 T5 c E2* abcd 7 9Abcd 7 1AAA.AAA.bcdef aBcd6a 123* abc2356.99 73000|Savoie index-tel|04|Rhône-Alpe -15 +36 5687 {15} exemple{36} il y a un truc et un truc et encore un truc et une chose chose et truc ne font pas bon ménage 123.3456.abc trucchosetruc tructructruc chosechosechose
grep "1A\{3\}\.A\{3\}\..*" liste4-spec
7 1AAA.AAA.bcdef aBcd6a 123*
grep "[0-9]\{1,3\}" liste4-spec
T5c Kc5 T5 c E2* abcd 7 9Abcd 7 1AAA.AAA.bcdef aBcd6a 123* abc2356.99 73000|Savoie index-tel|04|Rhône-Alpe -15 +36 5687 {15} exemple{36} 123.3456.abc
grep "[0-9]\{4,\}" liste4-spec
abc2356.99 73000|Savoie -15 +36 5687 {15} exemple{36} 123.3456.abc
grep "\( [0-9]\{4\}\)" liste4-spec
-15 +36 5687 {15} exemple{36}
[[:alnum:]] | Alpha-numerique [a-z A-Z 0-9] |
[[:alpha:]] | Alphabetic [a-z A-Z] |
[[:blank:]] | Espaces ou tabulations |
[[:cntrl:]] | Caractères de contrôle |
[[:digit:]] | Nombres [0-9] |
[[:graph:]] | Tous les caractères visibles (à l'exclusion des espaces) |
[[:lower:]] | Lettres minuscules [a-z] |
[[:print:]] | Caractères imprimables (tous caractères sauf ceux de contrôle) |
[[:punct:]] | Les caractères de ponctuation |
[[:space:]] | Les espaces |
[[:upper:]] | Les lettres majuscules [A-Z] |
[[:xdigit:]] | Chiffres hexadécimaux [0-9 a-f A-F] |
Avec grep, elles ne nécessitent pas l'option -R ou egrep.
grep "[[:digit:]]" liste1-nom
1 2 Francine 2 3 Édith 3 4 Géraldine 123 AAAAAA 4 5 Béatrice 5 6 Christelle 5 7 Dorothée 6 8 Amanda
option –regex : Interpréter tous les “PATTERNs” (modèles) comme des expressions rationnelles étendues.
option : -regextype “posix-extended”
option -r, bien que les classes relèvent des ERb.
expressions | Modèles reconnus |
---|---|
? | zéro ou une fois le caractère ou le regroupement précédent |
+ | une à n fois le caractère ou regroupement précédent |
{m} | m fois le caractère précédent |
{m,} | m fois le caractère précédent |
{m,n} | entre m et n fois le caractère précédent |
( er1) | regroupement |
er1|er2|er3 | alternative |
(er)+ | Une ou plus de une chaîne(s) consécutive(s) validée(s) “er”. |
(er)* | zéro ou plus de zéro chaîne(s) consécutive(s) validée(s) par “er” |
(er)? | une chaîne bulle ou toute chaîne validée par “er”. |
[c1c2...] | Tout caractère expressément listé entre les crochets. |
[^c1c2...] | Tout caractère excepté ceux qui sont expressément listés entre les crochets. |
[c1-c2] | Tout caractère appartenant à l’intervalle c1 c2, bornes comprises. |
er1|er2 | Toute chaîne de caractères validée soit par er1 soit par er2. |
(er)(er) | Toute chaîne validée par l’expression er, chaîne vide exclue. |
(er1)(er2) | Toute chaîne de caractères de type AB, dans laquelle l’expression régulière er1 valide A et l’expression régulière er2 valide B. Avec awk uniquement |
Excepté (er1)(er2)
:
grep -E "1([A-Z]){2}.*" liste4-spec
7 1AAA.AAA.bcdef aBcd6a 123*
Séquences | Séquences |
---|---|
\f | Produit ou correspond à un saut |
\n | Produit ou correspond à un retour à la ligne |
\t | Produit ou correspond à un onglet horizontal |
\v | Produit ou correspond à une tabulation verticale |
\w | Synonyme de [[:alnum:]] → correspond à un mot. |
\W | Synonyme de [^[:alnum]] → ce qui autre qu'un mot. |
\b | Correspond à une chaîne vide (blanc) à l'extrémité d'un mot |
Séquences | Séquences |
---|---|
\b | backspace (supprime le dernier caractère d'une chaîne) |
\f | formfeed (nouvelle page) |
\r | carriage return (retour à la ligne) |
\t | tabulation (crée une tabulation de dix espaces) |
\c | tout caractère pris sous sa forme littérale excepté \ |
Excepté (er1)(er2)
:
Options nécessaires avec find et locate :