Eliminar la línea que contiene cierta cadena y la siguiente línea


71

yo uso esto

cat foo.txt | sed '/bar/d'

para eliminar líneas que contienen la cadena baren el archivo.

Sin embargo, me gustaría eliminar esas líneas y la línea directamente después de ella . Preferiblemente, en sed, awku otra herramienta que está disponible en MinGW32.

Es una especie de reverso de lo que puedo conseguir en grepcon -Ay -Bpara imprimir las líneas que coincidan, así como las líneas de antes / después de la línea encajada.

¿Hay alguna manera fácil de lograrlo?


2
Solo para información: estoy analizando registros en los que las entradas son de dos líneas. Así que quiero encontrar una entrada que coincida con el patrón y eliminarlo, así como la siguiente línea. Por lo tanto, no necesito manejar líneas de coincidencia consecutivas, pero gracias de todos modos por la integridad de sus respuestas.
jakub.g

Respuestas:


75

Si tiene GNU sed (por lo tanto, Linux o Cygwin no incrustado):

sed '/bar/,+1 d'

Si tiene bardos líneas consecutivas, esto eliminará la segunda línea sin analizarla. Por ejemplo, si tiene un archivo de 3 líneas bar/ bar/ foo, la foolínea permanecerá.


1
+1 para la longitud :) En mi ejemplo particular, no tengo bars consecutivos , por lo que este es muy fácil de recordar.
jakub.g

11
sed '/bar/d'si solo desea "Eliminar la línea que contiene cierta cadena" y no la siguiente.
AJP

Si quiero eliminar todas las líneas después de las matemáticas, ¿entonces?
Pandya

1
@Pandya Eso es diferente. Puedes usar, por ejemplosed '/math/q'
Gilles 'SO- deja de ser malvado'

1
@AK Si solo quieres eliminar la línea correspondiente, es aún más simple:sed '/bar/d'
Gilles 'SO- deja de ser malvado'

16

Si barpuede ocurrir en líneas consecutivas, puede hacer:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

que se puede adaptar para eliminar más de 2 líneas cambiando las 2 anteriores con el número de líneas para eliminar, incluida la coincidente.

Si no, se hace fácilmente sedcon la solución @MichaelRollins o:

sed '/bar/,/^/d' < infile > outfile

La otra ventaja en la solución AWK es que puedo reemplazar /bar/con /bar|baz|whatever/. En sedesa sintaxis no parece funcionar.
jakub.g

@ jakub.g, tengo GNU sed (v4.4 ahora). No estoy seguro de los demás. Lo que sé es que usa la sintaxis de expresión regular "básica" de forma predeterminada, es por eso que su ejemplo no funcionó. Para lograr lo que desea, puede colocar una barra diagonal inversa frente a cada línea vertical o puede solicitar el seduso de expresiones regulares "extendidas". Más información aquí: gnu.org/software/sed/manual/html_node/… . Tenga en cuenta que esto también es aplicable grep. Aquí está mi propio ejemplo de trabajo: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.
Victor Yarema

12

No soy fluido en sed, pero es fácil hacerlo en awk:

awk '/bar/{getline;next} 1' foo.txt 

El script awk dice: para una línea que contiene una barra, obtenga la siguiente línea (getline), luego omita todo el procesamiento posterior (siguiente). El patrón 1 al final imprime las líneas restantes.

Actualizar

Como se señaló en el comentario, la solución anterior no funcionó con consecutivos bar. Aquí hay una solución revisada, que lo tiene en cuenta:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

Ahora seguimos leyendo para omitir todas las / bar / líneas.


1
Para replicar el grep -A100%, también debe manejar cualquier número de barlíneas consecutivas correctamente (eliminando todo el bloque y 1 línea después).
jw013

7

Deberá utilizar las capacidades de scripting de sed para lograr esto.

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

Data de muestra:

$ cat sample1.txt 
foo
bar
biz
baz
buz

El comando "N" agrega la siguiente línea de entrada en el espacio del patrón. Esto combinado con la línea de la coincidencia de patrón (/ bar /) serán las líneas que desea eliminar. Luego puede eliminar normalmente con el comando "d".


¿Cómo escribo una nueva línea en la consola? ¿O esto es solo script?
jakub.g

@ jakub.g: con GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus

2

Si alguna línea inmediatamente después de un partido se debe eliminar, entonces su sedprograma tendrá que considerar partidos consecutivos. En otras palabras, si elimina una línea que sigue a una coincidencia que también coincide, entonces probablemente también debería eliminar la línea que sigue a esa coincidencia.

Se implementa simplemente, pero hay que mirar un poco hacia atrás.

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

Funciona intercambiando espacios de espera y patrón para cada línea leída, por lo que la última línea se puede comparar con la actual cada vez. Entonces, cuando sedlee una línea, intercambia el contenido de sus búferes, y la línea anterior es el contenido de su búfer de edición, mientras que la línea actual se coloca en el espacio de espera.

Por lo tanto, sedcomprueba la línea anterior para una coincidencia y match, si !no se encuentra, se ejecutan las dos expresiones en la {función }. sedvoluntad gy el espacio de la bodega al sobrescribir el espacio de patrones - lo que significa que la línea actual es entonces tanto en los espacios de bodega y el patrón - y entonces //comprobar que para un partido a su expresión regular más recientemente compilado - match- y si él no lo hace matchse esta printed

Esto significa que una línea solo se imprime si no lo hace y la línea inmediatamente anterior no . También renuncia a cualquier intercambio innecesario por secuencias de es.match matchmatch

Si desea una versión que pueda eliminar un número arbitrario de líneas después de una match, necesitaría un poco más de trabajo:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... reemplace el 5 con el número de líneas (incluida la línea coincidente) que desea eliminar ...


1
2
3
4
12
13
14
21
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.