Con el bashshell, 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 charactersy 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 sedpuede aceptar nuevas líneas en el lado derecho del comando (por lo tanto, la other characterscadena), pero no en el izquierdo.
¿Hay alguna manera (más simple que esto ) de obtener este resultado con sedo grep?
text-processing
sed
grep
newlines
BowPark
fuente
fuente

\ndeclaració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ássedrechazarán ese escape en el lado derecho. aún así, el\nescape funcionará a la izquierda en cualquier POSIXsedy puede traducirlos de forma portátil comoy/c/\n/si tuviera el mismo efectos/c/\n/gy no siempre es tan útil.Respuestas:
Tres
sedcomandos 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
seds 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
Ncomando ext para agregar la siguiente línea de entrada al espacio de patrón siguiendo un\ncarácter de línea de flujo. Cualquiera que haya estadosedingiriendo durante un tiempo habrá aprendido a confiar en el\npersonaje 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;
sedactú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;Dbucle muy simple . Estos tres comandos están integrados en cualquier compatible con POSIXsedy se complementan muy bien entre sí.N- como ya se mencionó, agrega laNlínea de entrada ext al espacio de patrón después de un\ndelimitador de línea e insertado .P- comop; quePRints patrón espacio - pero sólo hasta a la primera que ocurre\ncarácter ewline. Y así, dada la siguiente entrada / comando:printf %s\\n one two | sed '$!N;P;d'sedPrints solo uno . Sin embargo, con ...D- comod; queDeletes patrón-espacio y comienza otro ciclo-line. A diferenciad,Delimina solo hasta la primera línea de\nflujo que ocurre en el espacio de patrones. Si hay más en el espacio de patrón después del\ncarácter de línea ew,sedcomienza el siguiente ciclo de línea con lo que queda. Siden el ejemplo anterior se reemplazara con aD, por ejemplo,sedsePborrarí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\new añadidaN, nunca queda nada cuando sesedDelige el espacio de patrón.Se podrían hacer pruebas para aplicar el
Py / oDselectivamente, 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
:brancho /test (como también se demuestra en la respuesta de Joeseph R. aquí ) y vuelven a ella dadas ciertas condiciones.-e :n -e- lossedscripts portátiles delimitarán una:definición de etiqueta con un\newline o una nueva-edeclaración de ejecución en línea .:n- define una etiqueta llamadan. Esto se puede devolver en cualquier momento conbnotn.tn- eltcomando 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ótests fue exitosa.En este comando, la recursión ocurre para las líneas coincidentes. Si
sedreemplaza con éxito el patrón con otros caracteres ,sedvuelve a la:netiqueta e intenta nuevamente. Sis///no se realiza unasedsustitució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 essedla prueba. Debido a que elbcomando ranch es una función de esta dirección,sedsolobregresará a ranch:ndespués de que se\nagregue un ewline y el espacio de patrón todavía termine con una"comilla doble.Se hace el menor tiempo posible entre
Nyb, de esta manera, sesedpuede 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 lagbandera 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
DATAy cómo recibe la entrada de texto?<<\DATA\ntext input\nDATA\nestá integrado , pero ese es solo el texto entregadosedpor el shell en un documento aquí . Funcionaría tan bien comosed 'script' filenameoprocess that writes to stdout | sed 'script'. ¿Eso ayuda?Dcada línea modificada es doble? (LosedDporque, de loDcontrario,Delige de la salida lo que ahora ves duplicado. Acabo de hacer una edición, y también puedo ampliarla pronto.Dcosa.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
-00hace que Perl lea el archivo en "modo párrafo", lo que significa que las "líneas" se definen en\n\nlugar 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\nsorber 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
awkdeberí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 otrosseds requerirán un\newline o un-edescanso entrepy}. Puede evitar los corchetes por completo, y de forma portátil, e incluso evitar insertar un carácter extra de línea de\ncable 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
:xes 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:xetiqueta (eso es lo quebxhace) y agrega otra línea al búfer y comienza a procesarla.fuente
sedque 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 otrosedfallará allí, y fallará porN. GNUsedrompe las pautas de POSIX para imprimir el espacio de patrón antes de salir en unNen la última línea, pero POSIX deja en claro que siNse lee un comando en la última línea, no se debe imprimir nada .vcomando de GNU que se interrumpe entre sí,sedpero 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'.