Alternance / ou opérateur regex (foo | bar) dans GNU ou BSD Sed
28
Je n'arrive pas à le faire fonctionner. La documentation de GNU sed dit d'échapper au tuyau, mais cela ne fonctionne pas, pas plus que l'utilisation d'un tuyau droit sans l'échappement. L'ajout de parens ne fait aucune différence.
$ echo 'cat
dog
pear
banana
cat
dog'| sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog
$ echo 'cat
dog
pear
banana
cat
dog'| sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog
echo 'cat dog pear banana cat dog'| sed -E -e 's/cat|dog/Bear/g'
et cela fonctionnera sur ces systèmes BSD, et sed -ravec GNU.
GNU sedsemble avoir un support totalement non documenté mais fonctionnel -E, donc si vous avez un script multi-plateforme limité à ce qui précède, c'est votre meilleure option. Comme il n'est pas documenté, vous ne pouvez probablement pas vraiment compter dessus.
Un commentaire note que les versions BSD prennent -régalement en charge en tant qu'alias non documenté. OS X ne fonctionne toujours pas aujourd'hui et les anciennes machines NetBSD et OpenBSD auxquelles j'ai accès non plus, mais celle de NetBSD 6.1 le fait. Les Unités Commerciales que je peux atteindre universellement ne le font pas. Donc, avec tout cela, la question de la portabilité devient assez compliquée à ce stade, mais la réponse simple est de passer àawk si vous en avez besoin, qui utilise des ERE partout.
Les trois BSD que vous avez mentionnés prennent tous en charge l' -roption comme synonyme de -Ecompatibilité avec GNU sed. OpenBSD et OS X sed -Einterpréteront le tuyau échappé comme un tuyau littéral, et non comme un opérateur d'alternance. Voici un lien de travail vers la page de manuel NetBSD et en voici un pour OpenBSD qui n'a pas dix ans.
Cela se produit car il (a|b)s'agit d'une expression régulière étendue, et non d'une expression régulière de base. Utilisez l' -Eoption pour y faire face.
echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'
Depuis la sedpage de manuel:
-E Interpret regular expressions as extended (modern) regular
expressions rather than basic regular expressions (BRE's).
Notez que -rc'est un autre indicateur pour la même chose, mais il -Eest plus portable et sera même dans la prochaine version des spécifications POSIX.
La manière portable de le faire - et la manière la plus efficace - est d'utiliser les adresses. Tu peux le faire:
printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b'-e '};cBear'
De cette façon, si la ligne ne contient pas la chaîne cat et ne contient pas la chaîne dogsedb ranches hors du script, imprime automatiquement sa ligne actuelle et tire sur la ligne suivante pour commencer le cycle suivant. Par conséquent, il n'exécute pas l'instruction suivante - qui, dans cet exemple, csuspend la ligne entière pour lire Bear, mais il pourrait tout faire.
Il est probablement intéressant de noter également que toute déclaration suivante la !bdans cette sedcommande peut ne correspondre sur une ligne contenant soit la chaîne dogou cat- de sorte que vous pouvez effectuer d' autres tests sans danger de faire correspondre une ligne qui ne fonctionne pas - ce qui signifie que vous pouvez maintenant appliquer les règles à l'un ou à l'autre aussi.
Mais c'est la prochaine. Voici la sortie de la commande ci-dessus:
###OUTPUT###BearBear
pear
banana
BearBear
Vous pouvez également implémenter de manière portative une table de recherche avec des références arrières.
printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'
C'est beaucoup plus de travail à configurer pour ce cas d'exemple simple, mais cela peut rendre les sedscripts beaucoup plus flexibles à long terme.
Dans la première ligne, je xchange l'espace de maintien et l'espace de motif, puis insère le chien <space>chat à<space><space> cordes dans l'espace de maintien avant de les xchanger de nouveau.
À partir de là et sur chaque ligne suivante, je Gmaintiens l'espace ajouté à l'espace de motif, puis vérifie si tous les caractères depuis le début de la ligne jusqu'à ce que la nouvelle ligne que je viens d'ajouter à la fin correspondent à une chaîne entourée d'espaces après. Si c'est le cas, je remplace tout le lot par Bear et sinon il n'y a pas de mal parce que je Pn'imprime ensuite que jusqu'à la première nouvelle ligne apparaissant dans l'espace de motif, puis dje supprime tout cela.
###OUTPUT###BearBear
pear
banana
BearBear
Et quand je dis flexible, je le pense. Ici, il remplace chat avec Ours brun et chien avec Ours noir :
printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'###OUTPUT###BrownBearBlackBear
pear
banana
BrownBearBlackBear
Vous pouvez bien sûr développer beaucoup le contenu de la table de recherche - j'ai repris l'idée des courriels usenet de Greg Ubben sur le sujet quand, dans les années 90, il a décrit comment il a construit une calculatrice brute à partir d'une seule sed s///déclaration.
ouf, +1. Vous avez un penchant pour sortir des sentiers battus, je dois dire
iruvar
@ 1_CR - Voir ma dernière édition - pas mon idée - ce qui ne veut pas dire que je n'apprécie pas cela et le considère comme un compliment. Mais j'aime rendre hommage quand c'est dû.
mikeserv
1
c'est une question assez ancienne, mais au cas où quelqu'un voudrait essayer, il y a un moyen d'effort assez faible pour le faire dans sed avec les fichiers sed. Chaque option peut être répertoriée sur une ligne distincte, et sed évaluera chacune. C'est un équivalent logique de ou. Par exemple, pour supprimer des lignes contenant un certain code:
tu peux dire : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'
Voici une technique qui n'utilise aucune option spécifique à l'implémentation sed(par exemple -E, -r). Au lieu de décrire le modèle comme une seule expression régulière cat|dog, nous pouvons simplement l'exécuter seddeux fois:
echo 'cat
dog
pear
banana
cat
dog'| sed 's/cat/Bear/g'| sed 's/dog/Bear/g'
C'est vraiment une solution de contournement évidente, mais qui mérite d'être partagée. Il se généralise naturellement à plus de deux chaînes de motif, bien qu'une très longue chaîne de sedne soit pas trop belle.
J'utilise souvent sed -i(qui fonctionne de la même manière dans toutes les implémentations) pour apporter des modifications aux fichiers. Ici, une longue liste de chaînes de modèle peut être bien incorporée, car chaque résultat temporaire est enregistré dans le fichier:
for pattern in cat dog owl;do
sed -i "s/${pattern}/Bear/g" myfile
done
-r
option comme synonyme de-E
compatibilité avec GNU sed. OpenBSD et OS Xsed -E
interpréteront le tuyau échappé comme un tuyau littéral, et non comme un opérateur d'alternance. Voici un lien de travail vers la page de manuel NetBSD et en voici un pour OpenBSD qui n'a pas dix ans.-E
: developer.apple.com/library/mac/documentation/Darwin/Reference/…-E
gnu.org/software/sed/manual/sed.html#index-_002dE .Cela se produit car il
(a|b)
s'agit d'une expression régulière étendue, et non d'une expression régulière de base. Utilisez l'-E
option pour y faire face.Depuis la
sed
page de manuel:Notez que
-r
c'est un autre indicateur pour la même chose, mais il-E
est plus portable et sera même dans la prochaine version des spécifications POSIX.la source
La manière portable de le faire - et la manière la plus efficace - est d'utiliser les adresses. Tu peux le faire:
De cette façon, si la ligne ne contient pas la chaîne cat et ne contient pas la chaîne dog
sed
b
ranches hors du script, imprime automatiquement sa ligne actuelle et tire sur la ligne suivante pour commencer le cycle suivant. Par conséquent, il n'exécute pas l'instruction suivante - qui, dans cet exemple,c
suspend la ligne entière pour lire Bear, mais il pourrait tout faire.Il est probablement intéressant de noter également que toute déclaration suivante la
!b
dans cettesed
commande peut ne correspondre sur une ligne contenant soit la chaînedog
oucat
- de sorte que vous pouvez effectuer d' autres tests sans danger de faire correspondre une ligne qui ne fonctionne pas - ce qui signifie que vous pouvez maintenant appliquer les règles à l'un ou à l'autre aussi.Mais c'est la prochaine. Voici la sortie de la commande ci-dessus:
Vous pouvez également implémenter de manière portative une table de recherche avec des références arrières.
C'est beaucoup plus de travail à configurer pour ce cas d'exemple simple, mais cela peut rendre les
sed
scripts beaucoup plus flexibles à long terme.Dans la première ligne, je
x
change l'espace de maintien et l'espace de motif, puis insère le chien<space>
chat à<space>
<space>
cordes dans l'espace de maintien avant de lesx
changer de nouveau.À partir de là et sur chaque ligne suivante, je
G
maintiens l'espace ajouté à l'espace de motif, puis vérifie si tous les caractères depuis le début de la ligne jusqu'à ce que la nouvelle ligne que je viens d'ajouter à la fin correspondent à une chaîne entourée d'espaces après. Si c'est le cas, je remplace tout le lot par Bear et sinon il n'y a pas de mal parce que jeP
n'imprime ensuite que jusqu'à la première nouvelle ligne apparaissant dans l'espace de motif, puisd
je supprime tout cela.Et quand je dis flexible, je le pense. Ici, il remplace chat avec Ours brun et chien avec Ours noir :
Vous pouvez bien sûr développer beaucoup le contenu de la table de recherche - j'ai repris l'idée des courriels usenet de Greg Ubben sur le sujet quand, dans les années 90, il a décrit comment il a construit une calculatrice brute à partir d'une seule
sed s///
déclaration.la source
c'est une question assez ancienne, mais au cas où quelqu'un voudrait essayer, il y a un moyen d'effort assez faible pour le faire dans sed avec les fichiers sed. Chaque option peut être répertoriée sur une ligne distincte, et sed évaluera chacune. C'est un équivalent logique de ou. Par exemple, pour supprimer des lignes contenant un certain code:
tu peux dire :
sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'
ou mettez ceci dans votre fichier sed:
la source
Voici une technique qui n'utilise aucune option spécifique à l'implémentation
sed
(par exemple-E
,-r
). Au lieu de décrire le modèle comme une seule expression régulièrecat|dog
, nous pouvons simplement l'exécutersed
deux fois:C'est vraiment une solution de contournement évidente, mais qui mérite d'être partagée. Il se généralise naturellement à plus de deux chaînes de motif, bien qu'une très longue chaîne de
sed
ne soit pas trop belle.J'utilise souvent
sed -i
(qui fonctionne de la même manière dans toutes les implémentations) pour apporter des modifications aux fichiers. Ici, une longue liste de chaînes de modèle peut être bien incorporée, car chaque résultat temporaire est enregistré dans le fichier:la source