Me di cuenta de que, si agrego \n
un patrón para sustituir el uso sed
, no coincide. Ejemplo:
$ cat > alpha.txt
This is
a test
Please do not
be alarmed
$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt
$ diff alpha.txt{,.original}
$ # No differences printed out
¿Cómo puedo hacer que esto funcione?
sed
regular-expression
utilities
Belmin Fernandez
fuente
fuente
Respuestas:
En la llamada más simple de sed , tiene una línea de texto en el espacio del patrón, es decir. 1 línea de
\n
texto delimitado de la entrada. La línea única en el espacio del patrón no tiene\n
... Es por eso que su expresión regular no encuentra nada.Puede leer varias líneas en el espacio de patrones y manipular cosas sorprendentemente bien, pero con un esfuerzo más que normal. Sed tiene un conjunto de comandos que permiten este tipo de cosas ... Aquí hay un enlace a un Resumen de comandos para sed . Es el mejor que he encontrado, y me puso en marcha.
Sin embargo, olvide la idea de "una línea" una vez que comience a usar los microcomandos de sed. Es útil diseñarlo como un programa estructurado hasta que lo sienta ... Es sorprendentemente simple e igualmente inusual. Se podría considerar como el "lenguaje ensamblador" de la edición de texto.
Resumen: use sed para cosas simples, y tal vez un poco más, pero en general, cuando va más allá de trabajar con una sola línea, la mayoría de las personas prefieren algo más ...
Dejaré que alguien más sugiera algo más ... Estoy realmente no estoy seguro de cuál sería la mejor opción (usaría sed, pero eso es porque no conozco a Perl lo suficientemente bien).
Aquí es el mismo guión, condensado en lo que obviamente es más difícil de leer y trabajar, pero algunos llamarían dudosamente una sola frase.
Aquí está mi comando "hoja de trucos"
fuente
t
comando aquí; cuando no se le da una etiqueta, el valor predeterminado es la bifurcación hasta el final del guión. Entonces,sed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;t;P;D}}' alpha.txt
hace exactamente lo mismo que su comando en todas las circunstancias. Por supuesto, para este archivo en particular ,sed '/test/{N;s/.*/not a test\nBe/}' alpha.txt
hace lo mismo también, pero mi primer ejemplo es lógicamente equivalente para todos los archivos posibles. También tenga\n
en cuenta que en una cadena de reemplazo no produce una nueva línea; necesita una barra invertida `\` seguida de una nueva línea real para hacerlo.#
comando no separado del anterior,\n
en RHS des
). Con GNUsed
también puede usar-z
para usar registros delimitados por NUL (y luego arrastrar toda la entrada si es texto (que por definición no contiene NUL)).Usar en
perl
lugar desed
:-pi -e
es su secuencia de línea de comandos estándar "reemplazar en el lugar", y -0777 hace que Perl sorba los archivos completos. Consulte perldoc perlrun para obtener más información al respecto.fuente
sed
y que aparezcan respuestas usando awk o perl. Creo que no está en el tema, por lo tanto, lo siento, pero despedí a uno menos.sed
respuesta anterior prueba que una respuesta de Perl está en el tema.Creo que es mejor reemplazar el
\n
símbolo con algún otro símbolo, y luego trabajar como de costumbre:por ejemplo, código fuente no trabajado:
se puede cambiar a:
Si alguien no lo sabe,
\n
es el final de línea UNIX,\r\n
- windows,\r
- Mac OS clásico. El texto normal de UNIX no usa el\r
símbolo, por lo que es seguro usarlo para este caso.También puede usar algún símbolo exótico para reemplazar temporalmente \ n. Como ejemplo - \ f (símbolo de alimentación de formulario). Puedes encontrar más símbolos aquí .
fuente
\r
en el argumentosed
con$(printf '\r')
.$
antes de la cadena sed para evitar que se convierta\r
en unr
. Ejemplo corto:sed $'s/\r/~/'
. Ejemplo completo:cat alpha.txt | tr '\n' '\r' | sed $'s/a test\rPlease do not/not a test\rBe/' | tr '\r' '\n'
A fin de cuentas , engullir todo el archivo puede ser la forma más rápida de hacerlo.
La sintaxis básica es la siguiente:
Eso sí, engullir todo el archivo puede no ser una opción si el archivo es tremendamente grande. Para tales casos, otras respuestas proporcionadas aquí ofrecen soluciones personalizadas que están garantizadas para funcionar en una pequeña huella de memoria.
Para todas las demás situaciones de pirateo y corte, el simple hecho de anteponer
-e '1h;2,$H;$!d;g'
seguido de sused
argumento original de expresiones regulares prácticamente hace el trabajo.p.ej
¿Qué
-e '1h;2,$H;$!d;g'
hacer?El
1
,2,$
,$!
las partes son línea de especificadores de ese límite que líneas el comando directamente siguiente se ejecuta en.1
: Solo en primera línea2,$
: Todas las líneas a partir de la segunda$!
: Cada línea que no sea la últimaAmpliado, esto es lo que sucede en cada línea de una entrada de línea N.
El
g
comando no tiene un especificador de línea, pero eld
comando anterior tiene una cláusula especial " Iniciar próximo ciclo ", y esto evita que seg
ejecute en todas las líneas, excepto en la última.En cuanto al significado de cada comando:
h
seguido deH
s en cada línea copia dichas líneas de entrada ensed
el espacio de espera . (Piense en un búfer de texto arbitrario).d
descarta cada línea para evitar que estas líneas se escriban en la salida. El espacio de la bodega sin embargo se conserva.g
restaura la acumulación de cada línea desde el espacio de espera para quesed
pueda ejecutar su expresión regular en toda la entrada (en lugar de una línea a la vez), y por lo tanto es capaz de partido en\n
s.fuente
sed
tiene tres comandos para gestionar varias líneas de operaciones:N
,D
yP
(comparar a la normalidadn
,d
yp
).En este caso, puede hacer coincidir la primera línea de su patrón, usar
N
para agregar la segunda línea al espacio del patrón y luego usars
para hacer su sustitución.Algo como:
fuente
G
,H
,x
...). Se pueden agregar más líneas al espacio del patrón con els
comando también.N
comandosPuedes pero es difícil . Recomiendo cambiar a una herramienta diferente. Si hay una expresión regular que nunca coincide con ninguna parte del texto que desea reemplazar, puede usarla como un separador de registro awk en GNU awk.
Si nunca hay dos líneas nuevas consecutivas en su cadena de búsqueda, puede usar el "modo de párrafo" de awk (una o más líneas en blanco separan los registros).
Una solución fácil es usar Perl y cargar el archivo completamente en la memoria.
fuente
perl -0777 -pe '…' <input-file >output-file
. Para modificar un archivo en su lugar,perl -0777 -i -pe '…' filename
sed
's-z
opción (añadido en 2012 después de que la respuesta fue publicada):seq 10 | sed -z 's/4\n5/a\nb/'
.Creo que esta es la solución sed para la coincidencia de 2 líneas.
Si quieres que coincidan 3 líneas, entonces ...
Si quieres que coincidan 4 líneas, entonces ...
Si la parte de reemplazo en el comando "s" reduce las líneas, entonces es un poco más complicado como este
Si la parte de reparación crece líneas entonces un poco más complicado como este
fuente
Aquí
/a test/,/Please do not/
se considera como un bloque de texto (de varias líneas),c
es el comando de cambio seguido de un nuevo textonot a test \nBe
En el caso de que el texto a reemplazar sea muy largo, sugeriría la sintaxis ex .
fuente
Simplemente amplíe un poco su ventana de entrada.
Es muy facil. Además de la sustitución estándar; sólo es necesario
$!N
,P
yD
aquí.fuente
Además de Perl, un enfoque general y útil para la edición multilínea de transmisiones (y archivos también) es:
Primero cree un nuevo separador de línea ÚNICO como desee, por ejemplo
Luego, en su comando sed (o cualquier otra herramienta), reemplace \ n por $ {S}, como
(awk reemplaza el separador de línea ASCII con el suyo y viceversa).
fuente
Esta es una pequeña modificación de la respuesta inteligente de xara para que funcione en OS X (estoy usando 10.10):
En lugar de usar explícitamente
\r
, tienes que usar$(printf '\r')
.fuente
printf '\r'
(oecho -e '\r'
) funcionan correctamente, tenga en cuenta que solo puede usar la sintaxis de shell$'\r'
para referirse a los literales escapados. Por ejemplo,echo hi$'\n'there
repetirá una nueva línea entrehi
ythere
. Del mismo modo, puede envolver toda la cadena para que cada barra invertida\
escape de su carácter posterior:echo $'hi\nthere'
Quería agregar algunas líneas de HTML a un archivo usando sed (y terminé aquí). Normalmente solo usaría perl, pero estaba en una caja que tenía sed, bash y no mucho más. Descubrí que si cambiaba la cadena a una sola línea y dejaba que bash / sed interpolara el \ t \ n todo salió bien:
Sería más limpio tener una función para escapar de las comillas dobles y las barras diagonales, pero a veces la abstracción es el ladrón del tiempo.
fuente
GNU
sed
tiene una-z
opción que permite usar la sintaxis que el OP intentó aplicar. ( página man )Ejemplo:
Tenga en cuenta: si usa
^
y$
ahora coinciden con el principio y el final de las líneas delimitadas con un carácter NUL (no\n
). Y, para garantizar que las coincidencias en todas sus\n
líneas ( separadas) estén sustituidas, no olvide usar elg
indicador para las sustituciones globales (por ejemplos/.../.../g
).Créditos: @ stéphane-chazelas mencionó por primera vez -z en un comentario anterior.
fuente
Sed rompe la entrada en las nuevas líneas. Mantiene solo una línea por bucle.
Por lo tanto, no hay forma de hacer coincidir una
\n
(nueva línea) si el espacio del patrón no lo contiene.Sin embargo, hay una manera de hacer que sed mantenga dos líneas consecutivas en el espacio del patrón utilizando el bucle:
Agregue cualquier procesamiento necesario entre la N y la P (reemplazando la
l
).En este caso (2 líneas):
O, para tres líneas:
Eso supone que se reemplace la misma cantidad de líneas.
fuente