Con el bash
shell, en un archivo con filas como las siguientes
first "line"
<second>line and so on
Me gustaría reemplazar una o más ocurrencias de "line"\n<second>
con other characters
y obtener cada vez:
first other characters line and so on
Así que tengo que reemplazar una cadena ambos con caracteres especiales como "
y <
y con un carácter de nueva línea.
Después de buscar entre las otras respuestas, descubrí que sed
puede aceptar nuevas líneas en el lado derecho del comando (por lo tanto, la other characters
cadena), pero no en el izquierdo.
¿Hay alguna manera (más simple que esto ) de obtener este resultado con sed
o grep
?
text-processing
sed
grep
newlines
BowPark
fuente
fuente
\n
declaración de ewline que haces es por eso que pregunto. las personas rara vez preguntan si pueden hacer lo mismos//\n/
que usted con GNUsed
, aunque la mayoría de los demássed
rechazarán ese escape en el lado derecho. aún así, el\n
escape funcionará a la izquierda en cualquier POSIXsed
y puede traducirlos de forma portátil comoy/c/\n/
si tuviera el mismo efectos/c/\n/g
y no siempre es tan útil.Respuestas:
Tres
sed
comandos diferentes :Los tres se basan en el
s///
comando básico de sustitución:También todos intentan tener cuidado en el manejo de la última línea, ya que los
sed
s tienden a diferir en su salida en casos extremos. Este es el significado de$!
una dirección que coincide con cada línea que!
no es la$
última.También usan el
N
comando ext para agregar la siguiente línea de entrada al espacio de patrón siguiendo un\n
carácter de línea de flujo. Cualquiera que haya estadosed
ingiriendo durante un tiempo habrá aprendido a confiar en el\n
personaje ewline, porque la única forma de obtener uno es ponerlo explícitamente allí.Los tres intentan leer con la menor cantidad de información posible antes de tomar medidas;
sed
actúa tan pronto como sea posible y no necesita leer un archivo de entrada completo antes de hacerlo.Aunque lo hacen todo
N
, los tres difieren en sus métodos de recursión.Primer comando
El primer comando emplea un
N;P;D
bucle muy simple . Estos tres comandos están integrados en cualquier compatible con POSIXsed
y se complementan muy bien entre sí.N
- como ya se mencionó, agrega laN
línea de entrada ext al espacio de patrón después de un\n
delimitador de línea e insertado .P
- comop
; queP
Rints patrón espacio - pero sólo hasta a la primera que ocurre\n
carácter ewline. Y así, dada la siguiente entrada / comando:printf %s\\n one two | sed '$!N;P;d'
sed
P
rints solo uno . Sin embargo, con ...D
- comod
; queD
eletes patrón-espacio y comienza otro ciclo-line. A diferenciad
,D
elimina solo hasta la primera línea de\n
flujo que ocurre en el espacio de patrones. Si hay más en el espacio de patrón después del\n
carácter de línea ew,sed
comienza el siguiente ciclo de línea con lo que queda. Sid
en el ejemplo anterior se reemplazara con aD
, por ejemplo,sed
seP
borraría uno y dos .Este comando solo se repite para las líneas que no coinciden con la
s///
instrucción de sustitución. Debido a que las///
sustitución elimina la línea de\n
ew añadidaN
, nunca queda nada cuando sesed
D
elige el espacio de patrón.Se podrían hacer pruebas para aplicar el
P
y / oD
selectivamente, pero hay otros comandos que se ajustan mejor a esa estrategia. Debido a que la recursividad se implementa para manejar líneas consecutivas que coinciden solo con una parte de la regla de reemplazo, las secuencias consecutivas de líneas que coinciden con ambos extremos de las///
sustitución no funcionan bien .:Dada esta entrada:
... imprime ...
Sin embargo, maneja
... bien.
Segundo comando
Este comando es muy similar al tercero. Ambos emplean una etiqueta de
:b
rancho /t
est (como también se demuestra en la respuesta de Joeseph R. aquí ) y vuelven a ella dadas ciertas condiciones.-e :n -e
- lossed
scripts portátiles delimitarán una:
definición de etiqueta con un\n
ewline o una nueva-e
declaración de ejecución en línea .:n
- define una etiqueta llamadan
. Esto se puede devolver en cualquier momento conbn
otn
.tn
- elt
comando est regresa a una etiqueta especificada (o, si no se proporciona ninguna, abandona el script para el ciclo de línea actual) si algunas///
sustitución desde que se definió la etiqueta o desde la última vez que se llamót
ests fue exitosa.En este comando, la recursión ocurre para las líneas coincidentes. Si
sed
reemplaza con éxito el patrón con otros caracteres ,sed
vuelve a la:n
etiqueta e intenta nuevamente. Sis///
no se realiza unased
sustitución, imprime automáticamente el espacio de patrón y comienza el siguiente ciclo de línea.Esto tiende a manejar mejor las secuencias consecutivas. Donde falló el último, esto imprime:
Tercer Comando
Como se mencionó, la lógica aquí es muy similar a la anterior, pero la prueba es más explícita.
/"$/bn
- Esta essed
la prueba. Debido a que elb
comando ranch es una función de esta dirección,sed
solob
regresará a ranch:n
después de que se\n
agregue un ewline y el espacio de patrón todavía termine con una"
comilla doble.Se hace el menor tiempo posible entre
N
yb
, de esta manera, sesed
puede recopilar rápidamente la mayor cantidad de información necesaria para garantizar que la siguiente línea no coincida con su regla. Las///
ubicación difiere aquí en que emplea lag
bandera lobal, por lo que hará todos los reemplazos necesarios a la vez. Dada una entrada idéntica, este comando sale idénticamente al último.fuente
DATA
y cómo recibe la entrada de texto?<<\DATA\ntext input\nDATA\n
está integrado , pero ese es solo el texto entregadosed
por el shell en un documento aquí . Funcionaría tan bien comosed 'script' filename
oprocess that writes to stdout | sed 'script'
. ¿Eso ayuda?D
cada línea modificada es doble? (Losed
D
porque, de loD
contrario,D
elige de la salida lo que ahora ves duplicado. Acabo de hacer una edición, y también puedo ampliarla pronto.D
cosa.Bueno, puedo pensar en un par de formas simples, pero ninguna involucra
grep
(que de todos modos no hace sustituciones) osed
.Perl
Para reemplazar cada aparición de
"line"\n<second>
conother characters
, use:O, para tratar múltiples ocurrencias consecutivas
"line"\n<second>
como una sola, y reemplazarlas por una solaother characters
, use:Ejemplo:
Esto
-00
hace que Perl lea el archivo en "modo párrafo", lo que significa que las "líneas" se definen en\n\n
lugar de\n
, esencialmente, que cada párrafo se trate como una línea. Por lo tanto, la sustitución coincide a través de una nueva línea.awk
La misma idea básica, configuramos el separador de registros (
RS
) para\n\n
sorber todo el archivo, luego el separador de registros de salida a nada (de lo contrario, se imprime una nueva línea adicional) y luego utilizamos lasub()
función para hacer el reemplazo.fuente
awk
debería serprint;}' file
. Necesito evitar Perl y usarlo preferiblementesed
, de todos modos sugirió buenas alternativas.lea todo el archivo y realice un reemplazo global:
fuente
${cmds}
es específico de GNU: la mayoría de los otrossed
s requerirán un\n
ewline o un-e
descanso entrep
y}
. Puede evitar los corchetes por completo, y de forma portátil, e incluso evitar insertar un carácter extra de línea de\n
cable en la primera línea como:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- sin embargo, esto se está volviendo imposible de mantener.Aquí hay una variante en la respuesta de Glenn que funcionará si tiene múltiples ocurrencias consecutivas (solo funciona con GNU
sed
):El
:x
es solo una etiqueta para ramificar. Básicamente, lo que esto hace es que comprueba la línea después de la sustitución y si aún coincide"line"
, se ramifica de nuevo a la:x
etiqueta (eso es lo quebx
hace) y agrega otra línea al búfer y comienza a procesarla.fuente
sed
que lleva su manejo de etiquetas no POSIX lo suficiente como para aceptar un espacio como delimitador para la declaración de etiquetas. Sin embargo, debe tener en cuenta que cualquier otrosed
fallará allí, y fallará porN
. GNUsed
rompe las pautas de POSIX para imprimir el espacio de patrón antes de salir en unN
en la última línea, pero POSIX deja en claro que siN
se lee un comando en la última línea, no se debe imprimir nada .v
comando de GNU que se interrumpe entre sí,sed
pero es un no-op en GNU versiones 4 y superiores.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.