Alternancia / operador Regex (foo | bar) en GNU o BSD Sed
28
Parece que no puedo hacer que funcione. La documentación de GNU sed dice escapar de la tubería, pero eso no funciona, ni usar una tubería recta sin la fuga. Agregar padres no hace ninguna diferencia.
$ 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'
y funcionará en esos sistemas BSD y sed -rcon GNU.
GNU sedparece tener un soporte totalmente indocumentado pero funcional -E, por lo que si tiene un script multiplataforma limitado a lo anterior, esa es su mejor opción. Sin embargo, dado que no está documentado, probablemente no pueda confiar en él.
Un comentario señala que las versiones BSD también son compatibles -rcon un alias no documentado. OS X todavía no lo hace hoy y las máquinas más antiguas de NetBSD y OpenBSD a las que tengo acceso tampoco, pero la NetBSD 6.1 sí. Los Unices comerciales que puedo alcanzar universalmente no lo hacen. Entonces, con todo eso, la pregunta de portabilidad se está volviendo bastante complicada en este momento, pero la respuesta simple es cambiar aawk si lo necesita, que usa ERE en todas partes.
Los tres BSD se mencionan todo el apoyo de la -ropción como sinónimo de -Ela compatibilidad con sed de GNU. OpenBSD y OS X sed -Einterpretarán la tubería escapada como una tubería literal, no como un operador de alternancia. Aquí hay un enlace de trabajo a la página de manual de NetBSD y aquí hay uno para OpenBSD que no tiene diez años.
La forma portátil de hacer esto, y la forma más eficiente, es con direcciones. Puedes hacerlo:
printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b'-e '};cBear'
De esta manera, si la línea no contiene el gato de cadena y no contiene los rangos del perro de cadena sedbfuera de la secuencia de comandos, imprime automáticamente su línea actual y tira de la siguiente para comenzar el siguiente ciclo. Por lo tanto, no realiza la siguiente instrucción, que en este ejemplo ccuelga toda la línea para leer Bear pero podría hacer cualquier cosa.
Probablemente valga la pena señalar también que cualquier instrucción que siga al comando !ben ese sedcomando solo puede coincidir en una línea que contenga la cadena dogo cat, por lo que puede realizar más pruebas sin peligro de coincidir con una línea que no lo hace, lo que significa que ahora puede aplicar reglas solo a uno u otro también.
Pero eso es lo siguiente. Aquí está la salida del comando anterior:
###OUTPUT###BearBear
pear
banana
BearBear
También puede implementar de forma portátil una tabla de búsqueda con referencias posteriores.
printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'
Es mucho más trabajo configurarlo para este caso de ejemplo simple, pero puede hacer sedscripts mucho más flexibles a largo plazo.
En la primera línea, xcambio el espacio de espera y el espacio de patrón, luego inserto el perro <space>gato de<space><space> cuerda en el espacio de espera antes de xvolver a cambiarlos.
De ahí en adelante y en cada línea siguiente, mantengo el Gespacio agregado al espacio del patrón, luego verifico si todos los caracteres desde el comienzo de la línea hasta la nueva línea que acabo de agregar al final coinciden con una cadena rodeada de espacios después. Si es así, reemplazo todo el lote con Bear y, si no, no hay ningún daño porque la próxima vez que llevo Psolo hasta la primera línea nueva en el espacio del patrón, delijo todo.
###OUTPUT###BearBear
pear
banana
BearBear
Y cuando digo flexible, lo digo en serio. Aquí está reemplazando el gato con BrownBear y el perro con BlackBear :
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
Por supuesto, puede ampliar mucho el contenido de la tabla de búsqueda: tomé la idea de los correos electrónicos de Usenet de Greg Ubben sobre el tema cuando, en los años 90, describió cómo construyó una calculadora cruda a partir de una sola sed s///declaración.
phew, +1. Tengo una inclinación por pensar fuera de la caja, debo decir
iruvar
@ 1_CR - Vea mi última edición, no es mi idea, lo que no quiere decir que no aprecio eso y lo considero un cumplido. Pero me gusta dar crédito donde es debido.
mikeserv
1
Esta es una pregunta bastante antigua, pero en caso de que alguien quiera intentarlo, hay una forma bastante baja de hacerlo en sed con archivos sed. Cada opción se puede enumerar en una línea separada, y sed evaluará cada una. Es un equivalente lógico de o. Por ejemplo, para eliminar líneas que contienen un código determinado:
puedes decir : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'
Aquí hay una técnica que no utiliza ninguna opción específica de implementación para sed(por ejemplo -E, -r). En lugar de describir el patrón como una única expresión regular cat|dog, simplemente podemos ejecutar seddos veces:
echo 'cat
dog
pear
banana
cat
dog'| sed 's/cat/Bear/g'| sed 's/dog/Bear/g'
Es una solución obvia realmente, pero vale la pena compartirla. Naturalmente, se generaliza a más de dos cadenas de patrones, aunque una cadena muy larga de sed's' no es demasiado atractiva.
A menudo uso sed -i(que funciona igual en todas las implementaciones) para hacer cambios en los archivos. Aquí, se puede incorporar una larga lista de cadenas de patrones, ya que cada resultado temporal se guarda en el archivo:
for pattern in cat dog owl;do
sed -i "s/${pattern}/Bear/g" myfile
done
-r
opción como sinónimo de-E
la compatibilidad con sed de GNU. OpenBSD y OS Xsed -E
interpretarán la tubería escapada como una tubería literal, no como un operador de alternancia. Aquí hay un enlace de trabajo a la página de manual de NetBSD y aquí hay uno para OpenBSD que no tiene diez años.-E
: developer.apple.com/library/mac/documentation/Darwin/Reference/…-E
gnu.org/software/sed/manual/sed.html#index-_002dE .Esto sucede porque
(a|b)
es una expresión regular extendida, no una expresión regular básica. Use la-E
opción para lidiar con esto.Desde la
sed
página del manual:Tenga en cuenta que
-r
es otro indicador para lo mismo, pero-E
es más portátil e incluso estará en la próxima versión de las especificaciones POSIX.fuente
La forma portátil de hacer esto, y la forma más eficiente, es con direcciones. Puedes hacerlo:
De esta manera, si la línea no contiene el gato de cadena y no contiene los rangos del perro de cadena
sed
b
fuera de la secuencia de comandos, imprime automáticamente su línea actual y tira de la siguiente para comenzar el siguiente ciclo. Por lo tanto, no realiza la siguiente instrucción, que en este ejemploc
cuelga toda la línea para leer Bear pero podría hacer cualquier cosa.Probablemente valga la pena señalar también que cualquier instrucción que siga al comando
!b
en esesed
comando solo puede coincidir en una línea que contenga la cadenadog
ocat
, por lo que puede realizar más pruebas sin peligro de coincidir con una línea que no lo hace, lo que significa que ahora puede aplicar reglas solo a uno u otro también.Pero eso es lo siguiente. Aquí está la salida del comando anterior:
También puede implementar de forma portátil una tabla de búsqueda con referencias posteriores.
Es mucho más trabajo configurarlo para este caso de ejemplo simple, pero puede hacer
sed
scripts mucho más flexibles a largo plazo.En la primera línea,
x
cambio el espacio de espera y el espacio de patrón, luego inserto el perro<space>
gato de<space>
<space>
cuerda en el espacio de espera antes dex
volver a cambiarlos.De ahí en adelante y en cada línea siguiente, mantengo el
G
espacio agregado al espacio del patrón, luego verifico si todos los caracteres desde el comienzo de la línea hasta la nueva línea que acabo de agregar al final coinciden con una cadena rodeada de espacios después. Si es así, reemplazo todo el lote con Bear y, si no, no hay ningún daño porque la próxima vez que llevoP
solo hasta la primera línea nueva en el espacio del patrón,d
elijo todo.Y cuando digo flexible, lo digo en serio. Aquí está reemplazando el gato con BrownBear y el perro con BlackBear :
Por supuesto, puede ampliar mucho el contenido de la tabla de búsqueda: tomé la idea de los correos electrónicos de Usenet de Greg Ubben sobre el tema cuando, en los años 90, describió cómo construyó una calculadora cruda a partir de una sola
sed s///
declaración.fuente
Esta es una pregunta bastante antigua, pero en caso de que alguien quiera intentarlo, hay una forma bastante baja de hacerlo en sed con archivos sed. Cada opción se puede enumerar en una línea separada, y sed evaluará cada una. Es un equivalente lógico de o. Por ejemplo, para eliminar líneas que contienen un código determinado:
puedes decir :
sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'
o pon esto en tu archivo sed:
fuente
Aquí hay una técnica que no utiliza ninguna opción específica de implementación para
sed
(por ejemplo-E
,-r
). En lugar de describir el patrón como una única expresión regularcat|dog
, simplemente podemos ejecutarsed
dos veces:Es una solución obvia realmente, pero vale la pena compartirla. Naturalmente, se generaliza a más de dos cadenas de patrones, aunque una cadena muy larga de
sed
's' no es demasiado atractiva.A menudo uso
sed -i
(que funciona igual en todas las implementaciones) para hacer cambios en los archivos. Aquí, se puede incorporar una larga lista de cadenas de patrones, ya que cada resultado temporal se guarda en el archivo:fuente