
Com grep
, quero selecionar todas as linhas que correspondem a um padrão e que não correspondem a outro padrão. Quero poder usar uma única invocação grep
para poder usar a --after-context
opção (or --before-context
, or --context
).
-v
não é viável aqui, pois nega todos os padrões que passo para grep
usar a -e
opção.
Exemplo
Quero procurar linhas correspondentes needle
, ignorando as linhas correspondentes ignore me
, com uma linha do seguinte contexto.
Aqui está meu arquivo de entrada:
one needle ignore me
two
three
four needle
five
A saída que eu quero é:
four needle
five
Como você pode ver, esta solução ingênua não funciona:
$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
Responder1
Se você possui GNU grep, você pode usarExpressões regulares Perl, que possuem umconstrução de negação.
grep -A1 -P '^(?!.*ignore me).*needle'
Se você não possui o GNU grep, você podeemular suas opções de contexto antes/depois no 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}
'
Responder2
Você parece estar usando GNUgrep. Com o GNU grep, você poderia passar o --perl-regex
sinalizador para ativar o PCRE e então fornecer uma afirmação antecipada negativa, exemplo abaixo
grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five
A principal coisa a notar aqui é que (?:(?!STRING).)*
é STRING
como [^CHAR]*
éCHAR
Responder3
Eu sugeriria usar o awk, pois ele lida melhor com E / S multilinha. Qualquer1)Canalize os resultados para GNU awk --\n
como separador de registros, ou2)Faça todas as correspondências no awk.
Opção 1
<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'
Saída:
four needle
five
--
Observe que esta opção pesquisa todo o registro ignore me
, define FS=1
e compara $1
para comparar apenas com a primeira linha.
opção 2
<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1