Comment enregistrez-vous une expression rationnelle complexe pour une réutilisation multiple dans sed?


12

En utilisant sed, je crée souvent des expressions régulières assez compliquées et complexes que je dois faire correspondre deux fois dans un fichier. Existe-t-il un moyen pour moi de sauvegarder cette expression régulière et de la référencer deux fois?

Peut-être quelque chose qui ressemble à ça?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Mise à jour: Une réponse a présenté la solution de l'utilisation d'une variable bash. Ça ne marche pas. Étant donné un test.txt.

#test.txt
foo bar
bar foo

Et le script

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Cela devrait produire la sortie

foo happy bar
bar foo

Mais à la place, j'obtiens l'erreur

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Si vous utilisez Perl, vous pouvez référencer les parties précédentes de l'expression dans l'expression:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
Lorsque vous trouvez quelque chose de trop compliqué pour sed, n'hésitez pas à opter pour awk ou perl.
Gilles 'SO- arrête d'être méchant'

2
@Cory: Votre exemple fonctionne très bien, si vous obtenez sa bonne syntaxe. Vous avez toujours la "$ variable" entre "guillemets simples" qui la cache de l'expansion du shell que vous attendez ... elle devrait l'êtresed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Réponses:


7

Vous pouvez utiliser des variables shell:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Je ne suis pas sûr de ce que vous vouliez dire $i, mais vous devrez peut-être le mettre en dehors des guillemets simples:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Bien sûr, cela ne fonctionne que si la sedcommande est invoquée à partir du shell, mais il existe une solution similaire avec presque tous les langages de programmation. (Et je ne pense pas qu'il soit possible d'utiliser des variables à l'intérieur sed.)
Stéphane Gimenez

Hrm. En essayant cela, les références inverses semblent être rompues. s/$complicated_regex/\1/donne une erreur indiquant qu'il s'agit d'une référence non valide.
Cory Klein,

Ah, peut-être ma faute, j'ai l'habitude des substitutions de variables zsh. Voir la réponse mise à jour.
Stéphane Gimenez

Vous devrez supprimer les ancres de la variable et les mettre dans le script sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman

Duh! Oui, j'ai oublié de vérifier que l'on m'a fourni une concaténation regex valide :-)
Stéphane Gimenez

0

Le moyen le plus simple de déposer une valeur de variable shell sedet de ne pas vous soucier de la façon dont votre barre oblique inverse doit changer pour le reste de votre sedscript, est de tout mettre entre guillemets, sauf la variable, et de le mettre entre guillemets.

Tous les exemples de code suivants supposent: VALUE='foo \([a-z]\+\)'

Le code cassé suivant échoue car la variable VALUEn'est pas développée:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Le code cassé suivant échoue parce que la barre oblique inverse \1est mangée par le shell (car elle est entre guillemets plutôt que entre guillemets simples) avant de la sedvoir:

sed "s/${VALUE}/foo happy \1/" test.txt

Le code suivant fonctionne comme prévu:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Le code suivant fonctionne également:

sed "s/${VALUE}/foo happy \\1/" test.txt

Il en va de même pour ce qui suit:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Mais pourquoi se compliquer? Les guillemets simples autour d'un sedscript rendent tout beaucoup plus clair, en particulier pour les gourous non scripteurs qui lisent votre code. Ma manière préférée est, encore une fois, de passer des guillemets simples aux guillemets doubles juste pour l'expansion variable et de revenir directement aux guillemets simples:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.