Tengo el siguiente código que eliminará líneas con el patrón banana
y 2 líneas después:
sed '/banana/I,+2 d' file
¡Hasta aquí todo bien! Pero lo necesito para eliminar 2 líneas antes banana
, pero no puedo obtenerlo con un "signo menos" o lo que sea (similar a lo que grep -v -B2 banana file
debería hacer, pero no lo hace):
teresaejunior@localhost ~ > LC_ALL=C sed '-2,/banana/I d' file
sed: invalid option -- '2'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,-2 d' file
sed: -e expression #1, char 16: unexpected `,'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,2- d' file
sed: -e expression #1, char 17: unknown command: `-'
shell-script
text-processing
sed
awk
Teresa e Junior
fuente
fuente
awk '{l[m=NR]=$0}/banana/{for(i=NR-2;i<=NR;i++)delete l[i]}END{for(i=1;i<=m;i++)if(i in l)print l[i]}'
. Esto no es eficiente, así que esto es solo una pista, no una solución.tac file | sed ... | tac
. : Psed '/banana/,+2d' file
eso también funcionaráawk 'tolower($0)~/bandana/{print prev[!idx];print prev[idx]} {idx=!idx;prev[idx]=$0}' filein
dado que este es un comentario y no una respuesta (ya hay otras respuestas), no entraré en demasiados detalles, pero el quid de la cuestión es que siempre tiene la dos registros anteriores en Anterior [0] y anterior [1], el "más fresco", según la iteración pero siempre enprev[idx]
, por lo que cuando se imprime, se imprimen en!idx
entoncesidx
orden. En cualquier caso, alterneidx
y coloque el registro actualprev[idx]
.Respuestas:
Sed no retrocede: una vez que se procesa una línea, se hace. Por lo tanto, "buscar una línea e imprimir las N líneas anteriores" no funcionará como está, a diferencia de "encontrar una línea e imprimir las siguientes N líneas", que es fácil de injertar.
Si el archivo no es demasiado largo, ya que parece estar bien con las extensiones GNU, puede usarlo
tac
para invertir las líneas del archivo.Otro ángulo de ataque es mantener una ventana deslizante en una herramienta como awk. Adaptación de ¿Hay alguna alternativa a los interruptores grep's -A -B -C (para imprimir algunas líneas antes y después)? (advertencia: mínimamente probado):
Uso:
/path/to/script -v pattern='banana' -v before=2
fuente
sed
también puede hacer ventanas deslizantes, pero el script resultante es típicamente tan ilegible que es más fácil de usarawk
.awk
guión no es del todo correcto; as-is imprime líneas en blanco y pierde las últimas líneas. Esto parece solucionarlo, pero puede no ser ideal o correcto en sí:if (NR-before in h) { print...; delete...; }
... y en laEND
sección:for (i in h) print h[i]
... Además, el script awk imprime la línea correspondiente, pero latac/sec
versión no; pero la pregunta es un poco ambigua en esto ... El script awk "original", al que proporcionó un enlace, funciona bien ... Me gusta ... No estoy seguro de cómo el 'mod' anterior afecta la impresión después de líneas ...Esto es bastante fácil con ex o vim -e
La expresión dice: por cada línea que contenga banana en el rango de la línea actual -2 a la línea actual, elimine.
Lo bueno es que el rango también puede contener búsquedas hacia adelante y hacia atrás, por ejemplo, esto eliminará todas las secciones del archivo que comienzan con una línea que contiene manzana y termina con una línea que contiene naranja y una línea con plátano:
fuente
Usando la "ventana deslizante" en
perl
:fuente
Puede hacer esto de manera bastante simple con
sed
:No sé por qué alguien diría lo contrario, pero para encontrar una línea e imprimir líneas anteriores se
sed
incorpora laP
primitiva\n
rint incorporada que escribe solo hasta el primer carácter de línea ewline en el espacio del patrón. LaD
primitiva elete complementaria elimina ese mismo segmento de espacio de patrón antes de reciclar recursivamente el script con lo que queda. Y para redondearlo, hay una primitiva para agregar laN
línea de entrada ext al espacio de patrón después de un\n
carácter de línea e insertado .Para que esa línea de
sed
sea todo lo que necesita. Simplemente lo reemplazasmatch
con lo que sea tu expresión regular y eres dorado. Esa también debería ser una solución muy rápida .Tenga en cuenta también que contará correctamente un
match
precedente inmediatomatch
como un disparador para silenciar la salida de las dos líneas anteriores y también silenciará su impresión:Para que funcione para un número arbitrario de líneas, todo lo que necesita hacer es obtener una pista.
Asi que:
... elimina las 5 líneas que preceden a cualquier coincidencia.
fuente
Utilizando
man 1 ed
:fuente