Quiero usar sedpara reemplazar cualquier cosa en una cadena entre la primera ABy la primera aparición de AC(inclusive) con XXX.
Por ejemplo , tengo esta cadena (esta cadena es solo para una prueba):
ssABteAstACABnnACss
y me gustaría una salida similar a la siguiente: ssXXXABnnACss.
Hice esto con perl:
$ echo 'ssABteAstACABnnACss' | perl -pe 's/AB.*?AC/XXX/'
ssXXXABnnACss
pero quiero implementarlo con sed. Lo siguiente (usando la expresión regular compatible con Perl) no funciona:
$ echo 'ssABteAstACABnnACss' | sed -re 's/AB.*?AC/XXX/'
ssXXXss
text-processing
sed
regular-expression
بارپابابا
fuente
fuente

Respuestas:
Las expresiones regulares de Sed coinciden con el partido más largo. Sed no tiene equivalente a no codicioso.
Obviamente lo que queremos hacer es unir
AB,seguido de
AC,seguido de
ACDesafortunadamente,
sedno puedo hacer el n. ° 2, al menos no para una expresión regular de varios caracteres. Por supuesto, para una expresión regular de un solo carácter como@(o incluso[123]), podemos hacer[^@]*o[^123]*. Por esto se puede evitar limitaciones de sed, cambiando todas las apariciones deACa@y luego la búsqueda deAB,seguido de
@,seguido de
@Me gusta esto:
La última parte cambia instancias inigualables de
@regreso aAC.Pero, por supuesto, este es un enfoque imprudente, ya que la entrada ya podría contener
@caracteres, por lo que, al unirlos, podríamos obtener falsos positivos. Sin embargo, dado que ninguna variable de shell tendrá nunca un carácter NUL (\x00), es probable que NUL sea un buen carácter para usar en la solución anterior en lugar de@:El uso de NUL requiere GNU sed. (Para asegurarse de que las características de GNU estén habilitadas, el usuario no debe haber configurado la variable de shell POSIXLY_CORRECT).
Si está utilizando sed con el
-zindicador de GNU para manejar la entrada separada por NUL, como la salida defind ... -print0, entonces NUL no estará en el espacio del patrón y NUL es una buena opción para la sustitución aquí.Aunque NUL no puede estar en una variable bash, es posible incluirlo en un
printfcomando. Si su cadena de entrada puede contener cualquier carácter, incluido NUL, consulte la respuesta de Stéphane Chazelas que agrega un método de escape inteligente.fuente
echooprintfun `\ 000 'bien en bash (o la entrada podría provenir de un archivo). Pero, en general, una cadena de texto probablemente no tenga NUL.ACdeAC@nuevo?Algunas
sedimplementaciones tienen soporte para eso.ssedtiene un modo PCRE:AT&T ast sed tiene conjunción y negación cuando se usan expresiones regulares aumentadas :
Portablemente, puede usar esta técnica: reemplace la cadena final (aquí
AC) con un solo carácter que no aparece en la cadena inicial o final (como:aquí) para que pueda hacerlos/AB[^:]*://, y en caso de que ese carácter pueda aparecer en la entrada , utilice un mecanismo de escape que no entre en conflicto con las cadenas de inicio y fin.Un ejemplo:
Con GNU
sed, un enfoque es utilizar la nueva línea como el personaje de reemplazo. Debido a quesedprocesa una línea a la vez, la nueva línea nunca ocurre en el espacio del patrón, por lo que se puede hacer:Eso generalmente no funciona con otras
sedimplementaciones porque no son compatibles[^\n]. Con GNUseddebe asegurarse de que la compatibilidad POSIX no esté habilitada (como con la variable de entorno POSIXLY_CORRECT).fuente
No, las expresiones regulares sed no tienen coincidencias no codiciosas.
Puede hacer coincidir todo el texto hasta la primera aparición
ACutilizando "cualquier cosa que no contengaAC" seguido deAC, que hace lo mismo que Perl.*?AC. La cuestión es que "cualquier cosa que no contengaAC" no se puede expresar fácilmente como una expresión regular: siempre hay una expresión regular que reconoce la negación de una expresión regular, pero la expresión regular de la negación se complica rápidamente. Y en sed portátil, esto no es posible en absoluto, porque la negación regex requiere agrupar una alternancia que está presente en expresiones regulares extendidas (por ejemplo, en awk) pero no en expresiones regulares básicas portátiles. Algunas versiones de sed, como GNU sed, tienen extensiones de BRE que permiten expresar todas las expresiones regulares posibles.Debido a la dificultad de negar una expresión regular, esto no se generaliza bien. Lo que puede hacer en su lugar es transformar la línea temporalmente. En algunas implementaciones de sed, puede usar nuevas líneas como marcador, ya que no pueden aparecer en una línea de entrada (y si necesita varios marcadores, use nueva línea seguida de un carácter variable).
Sin embargo, tenga en cuenta que la barra diagonal inversa no funciona en un juego de caracteres con algunas versiones sed. En particular, esto no funciona en GNU sed, que es la implementación de sed en Linux no incrustado; en GNU sed puedes usar
\nen su lugar:En este caso específico, es suficiente reemplazar el primero
ACpor una nueva línea. El enfoque que presenté anteriormente es más general.Un enfoque más poderoso en sed es guardar la línea en el espacio de espera, eliminar todo excepto la primera parte "interesante" de la línea, intercambiar el espacio de espera y el espacio de patrón o agregar el espacio de patrón al espacio de espera y repetir. Sin embargo, si comienza a hacer cosas que son tan complicadas, realmente debería pensar en cambiar a awk. Awk tampoco tiene una coincidencia no codiciosa, pero puede dividir una cadena y guardar las partes en variables.
fuente
s/\n//gelimina todas las líneas nuevas.sed - correspondencia no codiciosa por Christoph Sieghart
fuente
En su caso, puede negar el cierre de char de esta manera:
fuente
ABy la primera aparición deACconXXX...", y dassABteAstACABnnACsscomo ejemplo de entrada. Esta respuesta funciona para ese ejemplo , pero no responde la pregunta en general. Por ejemplo,ssABteCstACABnnACsstambién debería producir el resultadoaaXXXABnnACss, pero su comando pasa esta línea sin cambios.La solución es bastante simple.
.*es codicioso, pero no es absolutamente codicioso. Considera hacer coincidirssABteAstACABnnACsscontra la expresión regularAB.*AC. LoACque sigue.*debe tener una coincidencia. El problema es que debido a que.*es codicioso, el siguienteACcoincidirá con el último enAClugar del primero..*se come el primeroACmientras que el literalACen la expresión regular coincide con el último en ssABteAstACABnn AC ss. Para evitar que esto suceda, simplemente reemplace el primeroACcon algo ridículo para diferenciarlo del segundo y de cualquier otra cosa.El codicioso
.*ahora se detendrá al pie de-foobar-adentrossABteAst-foobar-ABnnACssporque no hay otro-foobar-que esto-foobar-, y la expresión regular-foobar-DEBE tener una coincidencia. El problema anterior era que la expresión regularACtenía dos coincidencias, pero como.*era codicioso,ACse seleccionó la última coincidencia . Sin embargo, con-foobar-solo una coincidencia es posible, y esta coincidencia demuestra que.*no es absolutamente codicioso. La parada de autobús para.*ocurre donde solo queda un partido para el resto de la expresión regular siguiente.*.Tenga en cuenta que esta solución fallará si
ACaparece una antes de la primeraABporqueACse reemplazará la incorrecta-foobar-. Por ejemplo, después de la primerasedsustitución, seACssABteAstACABnnACssconvierte en-foobar-ssABteAstACABnnACss; por lo tanto, no se puede encontrar una coincidencia en contraAB.*-foobar-. Sin embargo, si la secuencia es siempre ... AB ... AC ... AB ... AC ..., entonces esta solución tendrá éxito.fuente
Una alternativa es cambiar la cadena para que desee la coincidencia codiciosa
Use
revpara revertir la cadena, revierta sus criterios de coincidencia, usesedde la manera habitual y luego revierta el resultado ...fuente