varios usos uso usar una txt sustituir siguientes shells sera script salto reemplazar programacion por patrones parametros para palabra mas manejo líneas lineas linea las funciones eliminar ejemplos ejemplo devuelta desde cuál crear contenga contar con comando cero caracter cadenas buscar blanco avanzado archivos bash unix sed

bash - usos - Eliminar n1 líneas anteriores y n2 líneas siguientes con respecto a una línea que contiene un patrón



usar grep (5)

La idea es leer 5 líneas sin imprimirlas. Si encuentra el patrón, elimine las líneas no impresas y las 4 líneas abajo. Si no encuentra el patrón, recuerde la línea actual e imprima la primera línea no impresa. Al final, imprima lo que no está impreso.

sed -n -e ''/XXXX/,+4{x;s/.*//;x;d}'' -e ''1,5H'' -e ''6,${H;g;s//n//;P;s/[^/n]*//;h}'' -e ''${g;s//n//;p;d}'' fv.out

Por supuesto, esto solo funciona si tiene una ocurrencia de su patrón en el archivo. Si tiene muchas, necesita leer 5 líneas nuevas después de encontrar su patrón, y se vuelve complicado si vuelve a tener su patrón en esas líneas. En este caso, creo que sed no es la herramienta adecuada.

sed -e ''/XXXX/,+4d'' fv.out

Tengo que encontrar un patrón particular en un archivo y borrar 5 líneas arriba y 4 líneas debajo de él simultáneamente. Descubrí que la línea anterior elimina la línea que contiene el patrón y cuatro líneas debajo de ella.

sed -e ''/XXXX/,~5d'' fv.out

En el manual de sed se dio que ~ representa las líneas seguidas por el patrón. Pero cuando lo intenté, fueron las líneas que seguían el patrón que se borraron.

Entonces, ¿cómo elimino 5 líneas arriba y 4 líneas debajo de una línea que contiene el patrón simultáneamente?


Una solución que usa awk :

awk ''$0 ~ "XXXX" { lines2del = 5; nlines = 0; } nlines == 5 { print lines[NR%5]; nlines-- } lines2del == 0 { lines[NR%5] = $0; nlines++ } lines2del > 0 { lines2del-- } END { while (nlines-- > 0) { print lines[(NR - nlines) % 5] } }'' fv.out

Actualizar:

Este es el guión explicado:

  • Recuerdo las últimas 5 líneas en las lines matriz utilizando índices rotatorios (NR% 5; NR es el número de registro, en este caso, líneas).
  • Si encuentro el patrón en la línea actual ( $0 ~ "XXXX ; $0 es el registro actual: en este caso una línea, y ~ es el operador de coincidencia Expresión regular extendida ), restablezco el número de líneas leídas y las notas que tengo 5 líneas para eliminar (incluida la línea actual).
  • Si ya leí 5 líneas, imprimo la línea actual.
  • Si no tengo líneas para eliminar (lo cual también es cierto si he leído 5 líneas, pongo la línea actual en el búfer e incremento el número de líneas. Observe cómo se disminuye el número de líneas y luego se incrementa si una línea es impreso.
  • Si es necesario eliminar líneas, no imprimo nada y disminuyo el número de líneas para eliminar.
  • Al final del script, imprimo todas las líneas que están en el conjunto.

Mi versión original del script fue la siguiente, pero terminé optimizándola para la versión anterior:

awk ''$0 ~ "XXXX" { lines2del = 5; nlines = 0; } lines2del == 0 && nlines == 5 { print lines[NR%5]; lines[NR%5] } lines2del == 0 && nlines < 5 { lines[NR%5] = $0; nlines++ } lines2del > 0 { lines2del-- } END { while (nlines-- > 0) { print lines[(NR - nlines) % 5] } }'' fv.out

awk es una gran herramienta! Recomiendo encarecidamente que encuentres un tutorial en la red y lo leas. Una cosa importante: awk funciona con Extended Regular Expressions ( ERE ). Su sintaxis es un poco diferente de Standard Regular Expression ( RE ) que se usa en sed , pero todo lo que se puede hacer con RE se puede hacer con ERE.


Esto podría funcionar para usted:

sed ''H;$!d;g;s//([^/n]*/n/)/{5/}[^/n]*PATTERN/([^/n]*/n/)/{5/}//g;s/.//'' file

o esto:

awk --posix -vORS='''' -vRS=''([^/n]*/n){5}[^/n]*PATTERN([^/n]*/n){5}'' 1 file

una solución sed más eficiente:

sed '':a;/PATTERN/,+4d;//([^/n]*/n/)/{5/}/{P;D};$q;N;ba'' file


Una forma de usar sed , suponiendo que los patrones no son lo suficientemente cercanos entre sí:

Contenido de script.sed :

## If line doesn''t match the pattern... /pattern/ ! { ## Append line to ''hold space''. H ## Copy content of ''hold space'' to ''pattern space'' to work with it. g ## If there are more than 5 lines saved, print and remove the first ## one. It''s like a FIFO. //(/n[^/n]*/)/{6/}/ { ## Delete the first ''/n'' automatically added by previous ''H'' command. s/^/n// ## Print until first ''/n''. P ## Delete data printed just before. s/[^/n]*// ## Save updated content to ''hold space''. h } ### Added to fix an error pointed out by potong in comments. ### ======================================================= ## If last line, print lines left in ''hold space''. $ { x s/^/n// p } ### ======================================================= ## Read next line. b } ## If line matches the pattern... /pattern/ { ## Remove all content of ''hold space''. It has the five previous ## lines, which won''t be printed. x s/^.*$// x ## Read next four lines and append them to ''pattern space''. N ; N ; N ; N ## Delete all. s/^.*$// }

Correr como:

sed -nf script.sed infile


Si está satisfecho con la salida del resultado a un archivo en lugar de stdout, vim puede hacerlo de manera bastante eficiente:

vim -c ''g/pattern/-5,+4d'' -c ''w! outfile|q!'' infile

o

vim -c ''g/pattern/-5,+4d'' -c ''x'' infile

para editar el archivo en el lugar.