Yo uso esto
cat foo.txt | sed "/bar/d"
para eliminar las líneas que contienen la cadena bar
en el archivo.
Sin embargo, me gustaría eliminar esas líneas y la línea directamente después . Preferiblemente en sed
, awk
u otra herramienta que esté disponible en MinGW32.
Es una especie de reverso de lo que puedo obtener en grep
con -A
y -B
para imprimir también líneas coincidentes como líneas antes / después de la línea coincidente.
¿Hay alguna manera fácil de lograrlo?
Comentarios
- Solo para información: estoy ‘ analizando registros cuyas entradas son de dos líneas. Así que quiero encontrar una entrada que coincida con el patrón y eliminarla, 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!
Responder
Si tiene GNU sed (es decir, Linux no integrado o Cygwin):
sed "/bar/,+1 d"
Si tener bar
en dos 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 línea foo
permanecerá.
Comentarios
- +1 para la longitud 🙂 En mi particular ejemplo, no ‘ t tengo
bar
consecutivos, por lo que este es muy fácil de recordar. -
sed '/bar/d'
si solo desea » Eliminar la línea que contiene cierta cadena » y no el siguiente. - Si quiero eliminar todas las líneas después de las matemáticas, ¿entonces?
- @Pandya Eso ‘ es diferente. Puede utilizar, por ejemplo,
sed '/math/q'
- @ A.K. Si solo desea eliminar la línea coincidente, ‘ es aún más simple:
sed '/bar/d'
Respuesta
Si bar
puede aparecer 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 por el número de líneas a eliminar, incluida la correspondiente.
Si no es así, «se hace fácilmente en sed
con la solución @MichaelRollins» o:
sed "/bar/,/^/d" < infile > outfile
Comentarios
- La otra ventaja de la solución AWK es que puedo reemplazar
/bar/
con/bar|baz|whatever/
. Ensed
esa sintaxis no ‘ parece funcionar. - @ jakub.g, tengo GNU sed ( v4.4 ahora). No estoy seguro de los demás. Lo que sé es que utiliza la sintaxis de expresión regular » básica » de forma predeterminada. >
t trabajo. Para lograr lo que desea, puede poner una barra invertida delante de cada línea vertical o puede pedirle ased
que use » extendido » expresiones regulares. Más información aquí: gnu.org/software/sed/manual/html_node/…
. Tenga en cuenta que esto también se aplica agrep
. Aquí ‘ es mi propio ejemplo de trabajo:echo $'0a\n1b\n2c' | sed '/0a\|1b/d'
.
Responder
No hablo sed con fluidez, pero es fácil hacerlo en awk:
awk "/bar/{getline;next} 1" foo.txt
El El script awk dice: para una línea que contiene bar, obtenga la siguiente línea (getline), luego omita todo el procesamiento posterior (siguiente). El patrón 1 al final imprime las líneas restantes.
Actualización
Como se señaló en el comentario, la solución anterior no funcionó con bar
. Aquí hay una solución revisada, que la tiene en cuenta:
awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt
Ahora seguimos leyendo para omitir todas las líneas / bar /.
Comentarios
- Para replicar
grep -A
100%, también debes manejar cualquier número de líneas correctamente (eliminando todo el bloque y 1 línea después).
Responder
Querrá hacer uso de las capacidades de secuencias de comandos de sed «para lograr esto.
$ sed -e "/bar/ { $!N d }" sample1.txt
Datos 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 del patrón (/ barra /) serán las líneas que desea eliminar. Luego puede eliminar normalmente con el comando «d».
Comentarios
- ¿Cómo escribo una nueva línea en la consola? ¿O es solo un script?
- @ jakub.g: con GNU sed:
sed -e '/bar/{N;d}' sample1.txt
Respuesta
Si alguna línea inmediatamente después de una coincidencia debe eliminarse, su programa sed
tendrá que considerar coincidencias consecutivas. En otras palabras, si elimina una línea después de una coincidencia que también coincide, probablemente debería eliminar la línea que sigue a esa también.
Está implementado de manera bastante simple, pero debe mirar hacia atrás un poco. .
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 retención 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 sed
lee 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.
Entonces sed
busca en la línea anterior una coincidencia con match
, y si su !
no se encuentran las dos expresiones en la {
función }
se ejecutan. sed
g
establecerá el espacio de retención sobrescribiendo el espacio de patrón, lo que significa que la línea actual estará en ambos espacios de retención y de patrón. y luego //
comprobará si coincide con su expresión regular compilada más recientemente – match
– y si no match
es p
impreso.
Esto significa que una línea solo se imprime si no match
y la línea inmediatamente anterior no match
. También evita intercambios innecesarios por secuencias de match
es.
Si desea una versión que pueda eliminar un número arbitrario de líneas que ocurre después de un 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 le gustaría eliminar …
1 2 3 4 12 13 14 21