
Con grep
, quiero seleccionar todas las líneas que coincidan con un patrón y que no coincidan con otro patrón. Quiero poder usar una única invocación de grep
para poder usar la --after-context
opción (o --before-context
, o --context
).
-v
no es viable aquí, ya que niega todos los patrones que paso al grep
usar la -e
opción.
Ejemplo
Quiero buscar líneas que coincidan needle
, ignorando las líneas que coincidan ignore me
, con una línea del siguiente contexto.
Aquí está mi archivo de entrada:
one needle ignore me
two
three
four needle
five
El resultado que quiero es:
four needle
five
Como puede ver, esta solución ingenua no funciona:
$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
Respuesta1
Si tienes GNU grep, puedes usarExpresiones regulares en Perl, que tienen unconstructo de negación.
grep -A1 -P '^(?!.*ignore me).*needle'
Si no tienes GNU grep, puedesemular sus opciones de contexto antes/después en awk.
awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
for (i in h) {
print h[i];
delete h[i];
}
until = NR + after;
}
{
if (NR <= until) print $0; else h[NR] = $0;
delete h[NR-before];
}
END {exit !until}
'
Respuesta2
Parece que estás usando GNU.grep. Con GNU grep, puede pasar la --perl-regex
bandera para activar PCRE y luego proporcionar una aserción negativa de anticipación, como se muestra a continuación
grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five
Lo principal a tener en cuenta aquí es que (?:(?!STRING).)*
es STRING
como [^CHAR]*
esCHAR
Respuesta3
Sugeriría usar awk en su lugar, ya que maneja mejor la E/S multilínea. Cualquiera1)Canalice los resultados a GNU awk --\n
como separador de registros, o2)Haz todas las coincidencias en awk.
Opción 1
<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'
Producción:
four needle
five
--
Tenga en cuenta que esta opción busca en todo el registro ignore me
, establece FS=1
y compara $1
para comparar solo con la primera línea.
opcion 2
<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1