Pourquoi dois-je échapper des caractères regex dans sed pour être interprétés comme des caractères regex?

11

Il semble par exemple
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
que je dois échapper des caractères pour former une expression régulière. Dans ce cas, j'ai dû échapper à des accolades afin d'être interprété plusieurs fois.
Pourquoi? Je m'attendais à ce que tout soit un caractère regex à moins qu'il ne s'échappe. C'est le contraire.

Jim
la source
Il y avait un article sur la recherche dans Vim qui couvre quelque peu cette question, la version courte étant "cela dépend de l'implémentation de la commande" ... unix.stackexchange.com/questions/90345/…
Drav Sloan
@DravSloan: Je ne suis pas sûr que ce soit la même chose.Dans Vim, vous recherchez du texte par défaut et vous devez vous échapper pour rechercher des expressions rationnelles.Mais dans ce cas, le format attends/regex//g déjà une expression régulière et je m'attendrais à ce que ce soit du texte qui aurait besoin à échapper
Jim

Réponses:

14

En effet, sedutilise les BREIX POSIX (Expressions régulières de base) par opposition aux ERE (Expressions régulières étendues) auxquelles vous êtes probablement habitué de Perl ou d'amis.

Depuis la sed(1)page de manuel:

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

Citation pertinente du lien ci-dessus:

La saveur Basic Regular Expressions ou BRE standardise une saveur similaire à celle utilisée par la commande grep UNIX traditionnelle. C'est à peu près la plus ancienne saveur d'expression régulière encore en usage aujourd'hui. Une chose qui distingue cette saveur est que la plupart des métacaractères nécessitent une barre oblique inverse pour donner sa saveur au métacaractère. La plupart des autres versions, y compris POSIX ERE, utilisent une barre oblique inverse pour supprimer la signification des métacaractères.

Citation textuelle du commentaire de Craig Sanders :

Notez que dans GNU sed au moins, vous pouvez dire à sed d'utiliser des expressions rationnelles étendues avec l'option de ligne de commande -r ou --regexp-extended. Ceci est utile si vous souhaitez éviter d'uglifier votre script sed avec un échappement excessif.

Joseph R.
la source
1
Notez que dans GNU sed au moins, vous pouvez dire à sed d'utiliser des expressions rationnelles étendues avec l' option de ligne de commande -rou --regexp-extended. Ceci est utile si vous souhaitez éviter d'uglifier votre script sed avec un échappement excessif.
cas
@CraigSanders Merci pour cela. Ajouté pour répondre.
Joseph R.
@CraigSanders, d'autres sedimplémentations (quand elles prennent en charge les ERE, principalement les BSD) ont tendance à utiliser -Epour cela à la place (ce qui est beaucoup plus logique puisque c'est la même option que pour grep. Pourquoi GNU a sedchoisi -rest un mystère pour moi).
Stéphane Chazelas
oui, un mystère pour moi aussi. Il serait plus logique d'utiliser -E. puis ajoutez -F, -G et -P pour correspondre à GNU grep. IMO gawk bénéficierait également des mêmes arguments RE ... ou du moins, -P.
cas
12

C'est pour des raisons historiques.

Regexp a été introduit pour la première fois dans Unix dans l' edutilitaire au début des années 70. Bien que edse fondait sur qeddont la mise en œuvre par les mêmes auteurs compris regexp plus complexe, edne comprenait ^, $, [...], ., *et \d'échapper à tout ce qui précède.

Désormais, lorsque le besoin d'avoir plus d'opérateurs s'est fait sentir, il fallait trouver un moyen de les introduire sans rompre la compatibilité descendante. Si un script utilisait la s edcommande as s/foo() {/foo (var) {/gpour remplacer toutes les instances de foo() {with foo(var) { et que vous introduisiez un opérateur (or {, cela casserait ce script.

Cependant, aucun script ne ferait l'affaire s/foo\(\) {/foo\(var\) {/, car c'est la même chose s/foo() {/foo(var) {/et il n'y avait aucune raison de s'échapper (car il ne s'agissait pas d'un opérateur RE. Ainsi, l'introduction d'un nouvel opérateur \(ou \{n'interrompt pas la compatibilité descendante car il est très peu probable qu'il casse un script existant en utilisant l'ancienne syntaxe.

C'est donc ce qui a été fait. Plus tard, a \(...\)été ajouté initialement uniquement pour que la s edcommande fasse des choses comme s/foo\(.\)/\1bar/et plus tard grep '\(.\)\1'(mais pas des choses comme \(xx\)*).

Dans UnixV7 (1979, donc près d'une décennie plus tard), une nouvelle forme d'expressions régulières a été ajoutée dans le nouveau egrepet les awkutilitaires appelés expression régulière étendue (car ce sont de nouveaux outils, il n'y a pas de compatibilité descendante à rompre). Enfin, il a fourni les fonctionnalités disponibles dans l'ancien de Ken Thompson qed(opérateur d'alternance |, regroupement (..)*) et a ajouté quelques opérateurs comme +et ?(mais n'avait pas la fonction backref des expressions régulières de base).

Plus tard, les BSD ont ajouté \<et \>(à la fois à BRE et à ERE), et SysV a ajouté \{et \}à BRE uniquement.

Ce n'est que bien plus tard que {et }ont été ajoutés à ERE, par une telle compatibilité descendante. Tout le monde ne l'a pas ajouté. Par exemple, GNU awkjusqu'à la version 4.0.0 (2011) ne prenait pas en charge à {moins d'être forcé en mode de conformité POSIX.

quand GNU a grepété écrit au début des années 90, il a ajouté tous les goodies de BSD et SysV (comme \<, {) et au lieu d'avoir deux syntaxe regexp et moteur distincts pour BRE et ERE, a implémenté les mêmes opérateurs dans les deux, seuls les homologues BRE de (, ?, {, +doivent être précédés d'une barre oblique inverse (pour être compatible avec d' autres implémentations BRE). C'est pourquoi vous pouvez le faire .\+dans GNU grep(bien que ce ne soit pas POSIX ou pris en charge par d'autres implémentations) et vous pouvez le faire (.)\1dans GNU egrep(bien que ce ne soit pas POSIX ou pris en charge par de nombreuses autres implémentations, y compris GNU awk).

L'ajout d' \xopérateurs n'est pas le seul moyen d'ajouter plus d'opérateurs d'une manière rétrocompatible. Par exemple, perlutilisé (?...). C'est toujours rétrocompatible avec les ERE car il (?=...)n'est pas valide dans les ERE, de même pour .*?. vimpour des opérateurs similaires l'ont fait différemment en introduisant \@=ou .\{-}par exemple.

Stéphane Chazelas
la source