web-dev-qa-db-fra.com

Regex correct ne fonctionne pas dans grep

J'ai cette expression régulière:

(?<=prefix).*$

qui retourne n'importe quel caractère après la chaîne "prefix" et cela fonctionne très bien sur tous les moteurs regex en ligne (par exemple https://regex101.com ). Le problème est lorsque j'utilise cette expression régulière dans bash:

grep '(?<=prefix).*$' <<< prefixSTRING

cela ne correspond à rien. Pourquoi cette expression régulière ne fonctionne pas avec grep?

13
mark009

Vous semblez avoir défini l'expression rationnelle correcte, mais vous n'avez pas défini les indicateurs suffisants en ligne de commande pour que grep le comprenne. Parce que par défaut, grep prend en charge BRE et avec -E signaler qu'il fait ERE. Ce que vous avez (perspectives) n'est disponible que dans la version regex PCRE qui n'est prise en charge que dans GNU grep avec son -P drapeau.

En supposant que vous devez extraire uniquement la chaîne correspondante après prefix vous devez ajouter un indicateur supplémentaire -o pour faire savoir grep qui imprime uniquement la partie correspondante comme

grep -oP '(?<=prefix).*$' <<< prefixSTRING

Il existe également une version de grep qui prend en charge les bibliothèques PCRE par défaut - pcregrep dans laquelle vous pouvez simplement faire

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

Des explications détaillées sur les différentes saveurs regex sont expliquées dans ce merveilleux réponse de Giles et les outils qui les implémentent

38
Inian

Les expressions régulières se déclinent en de nombreuses saveurs différentes. Ce que vous montrez est une expression régulière de type Perl (PCRE, "Perl Compatible Regular Expression").

grep fait des expressions régulières POSIX. Ce sont expressions régulières de base (BRE) et expressions régulières étendues (ERE, si grep est utilisé avec l'option -E). Consultez le manuel de re_format Ou regex ou tout autre manuel similaire auquel votre manuel grep fait référence sur votre système, ou les textes standard POSIX auxquels je viens de me lier.

Si vous utilisez GNU grep, vous pourrez utiliser des expressions régulières de type Perl si vous utilisiez grep avec le GNU _ grep - option -P spécifique.

Notez également que grep renvoie lignes par défaut, pas des sous-chaînes de lignes. Encore une fois, avec GNU grep (et certaines autres implémentations grep), vous pouvez utiliser l'option -o Pour obtenir uniquement le ou les bits qui correspondent l'expression donnée de chaque ligne.

Notez que -P Et -o Sont des extensions non standard la spécification POSIX de grep .

Si vous n'utilisez pas GNU grep, vous pouvez utiliser sed à la place pour obtenir le bit entre la chaîne prefix et la fin de la ligne:

sed -n 's/.*prefix\(.*\)/\1/p' file

Cela ne fait qu'imprimer les lignes auxquelles sed parvient à appliquer la substitution donnée. La substitution remplacera la ligne entière qui correspond à l'expression (qui est un BRE), avec le morceau qui se produit après la chaîne prefix.

Notez que s'il y a plusieurs instances de prefix sur une ligne, la variation sed retournera la chaîne après la dernière une, tandis que la GNU grep la variation retournerait la chaîne après la première une (qui inclurait les autres instances de prefix).

La solution sed serait portable sur tous les systèmes de type Unix.

38
Kusalananda

Comme les autres réponses l'ont indiqué, grep n'utilise pas d'arôme regex avec lookbehinds (par défaut avec GNU grep, ou pas du tout avec les autres versions) .

Si vous ne pouvez pas utiliser GNU grep ou pcregrep, vous pouvez utiliser Perl si vous l'avez.

L'équivalent en ligne de commande avec Perl serait:

Perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

Vous placez l'expression régulière souhaitée entre les barres obliques. Comme vous utilisez Perl, cela utilise saveur regex de Perl .

6
quantum