regular - sed with regexp
Sed regex y subcadena negaciĆ³n (4)
Este tema puede ser antiguo, pero en aras de la integridad, ¿qué pasa con el operador de negación !
:
Haz que todos los infelices se vuelvan MUY FELICES:
echo -e ''happy/nhappy/nunhappy/nhappy'' | sed ''/^happy/! s/.*/VERY HAPPY/''
Encontré esto aquí: Cómo reemplazar cadenas en líneas que NO comienzan con un patrón determinado
¿Cuál es la sintaxis correcta para encontrar una subcadena (una cadena que está precedida y seguida por cadenas específicas) que no coincide con un patrón específico?
Por ejemplo, quiero tomar todas las subcadenas que comienzan con BEGIN_
, terminar con _END
y la subcadena intermedia no es igual a FOO
; y reemplace toda la subcadena con el formato "( subcadena interna )". Lo siguiente coincidiría:
-
BEGIN_bar_END
->(bar)
-
BEGIN_buz_END
->(buz)
-
BEGIN_ihfd8f398IHFf9f39_END
->(ihfd8f398IHFf9f39)
Pero BEGIN_FOO_END
no coincidiría.
He jugado con lo siguiente, pero parece que no puedo encontrar la sintaxis correcta:
sed -e ''s/BEGIN_(^FOO)_END/($1)/g''
sed -e ''s/BEGIN_([^FOO])_END/($1)/g''
sed -e ''s/BEGIN_(?!FOO)_END/($1)/g''
sed -e ''s/BEGIN_(!FOO)_END/($1)/g''
sed -e ''s/BEGIN_(FOO)!_END/($1)/g''
sed -e ''s/BEGIN_!(FOO)_END/($1)/g''
Esto podría funcionar para usted:
sed ''h;s/BEGIN_/(.*/)_END/(/1)/;/^(FOO)$/g'' file
Esto solo funciona si solo hay una cadena por línea.
Para múltiples cadenas por línea:
sed ''s/BEGIN_/([^F][^_]*/|F[^O][^_]*/|FO[^O][^_]*/|FOO[^_]/+/)_END//(/1/)/g'' file
O el más fácil de entender:
sed ''s//(BEGIN_/)FOO/(_END/)//1/n/2/g;s/BEGIN_/([^/n_]*/)_END/(/1/)/g;s//n/FOO/g'' file
No hay un operador de negación general en sed
, IIRC porque la compilación de expresiones regulares con negación a DFAs toma tiempo exponencial. Puedes solucionar esto con
''/BEGIN_FOO_END/b; s/BEGIN_/(.*/)_END/(/1)/g''
donde /BEGIN_FOO_END/b
significa: si encontramos BEGIN_FOO_END
, BEGIN_FOO_END
(saltamos) al final del script sed
.
No sé de una manera bonita, pero siempre podrías hacer esto:
$ cat file
BEGIN_FOO_END
BEGIN_FrOO_END
BEGIN_rFOO_END
$ sed ''/BEGIN_FOO_END/ !{s/BEGIN_/([^_]*/)_END/(/1)/}'' file
BEGIN_FOO_END
(FrOO)
(rFOO)