Gostaria de obter a correspondência de vários padrões com E entre padrões, ou seja, equivalente a executar vários greps em uma sequência:

grep pattern1 | grep pattern2 | ... 

Então, como convertê-lo em algo como?

grep pattern1 & pattern2 & pattern3 

Eu gostaria de usar o grep único porque estou construindo argumentos dinamicamente, então tudo tem que caber em uma string. Usar filtro é um recurso do sistema, não grep, portanto, não é um argumento para isso.


Não confunda esta pergunta com:

grep "pattern1\|pattern2\|..." 

Esta é uma OU correspondência de vários padrões.

Comentários

Resposta

agrep pode fazer isso com esta sintaxe:

agrep "pattern1;pattern2" 

Com GNU grep, quando construído w Com o suporte PCRE, você pode fazer:

grep -P "^(?=.*pattern1)(?=.*pattern2)" 

Com ast grep :

grep -X ".*pattern1.*&.*pattern2.*" 

(adicionando .* s como <x>&<y> corresponde a strings que correspondem a <x> e <y> exatamente , a&b nunca corresponderia, pois não existe tal string que pode ser a e b ao mesmo tempo).

Se os padrões não se sobrepõem, você também pode fazer:

grep -e "pattern1.*pattern2" -e "pattern2.*pattern1" 

A melhor forma portátil é provavelmente com awk como já mencionado:

awk "/pattern1/ && /pattern2/" 

Com sed:

sed -e "/pattern1/!d" -e "/pattern2/!d" 

Observe que todos terão sintaxe de expressão regular diferente.

Comentários

  • A sintaxe agrep não está funcionando para eu … em qual versão ele foi introduzido?
  • @Raman 2.04 de 1992 já o tinha. Eu ‘ não tenho motivo para acreditar que não ‘ lá desde o início. Versões mais recentes (após 1992) de agrep podem ser encontradas incluídas em glimpse / webglimpse . Possivelmente você tem uma implementação diferente. Porém, eu cometi um erro com a versão ast-grep, a opção para expressões regulares aumentadas é -X, não -A.
  • @St é phaneChazelas Obrigado, tenho agrep 0.8.0 no Fedora 23. Isso parece seja um agrep diferente daquele que você referencia.
  • @Raman, o seu parece TRE agrep .
  • @Techiee ou apenas awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Resposta

Você não especificou a versão do grep, isso é importante. Alguns mecanismos regexp permitem várias correspondências agrupadas por AND usando “& “mas este é um recurso não padrão e não portável. Mas, pelo menos GNU grep não suporta isso.

OTOH você pode simplesmente substituir grep por sed, awk, perl, etc. . (listados em ordem de aumento de peso). Com o awk, o comando seria semelhante a

 awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }" 

e pode ser construído para ser especificado na linha de comando de maneira fácil.

Comentários

  • Lembre-se de que awk usa ERE ‘ s, por exemplo o equivalente a grep -E, em oposição aos BRE ‘ s que grep simples usa.
  • awk ‘ s regexes são chamados EREs, mas na verdade eles ‘ é um pouco idiossincrático. Aqui estão provavelmente mais detalhes do que qualquer um gostaria: wiki.alpinelinux.org/wiki/Regex
  • Obrigado, grep 2.7.3 ( openSUSE). Votei em você, mas vou manter a questão aberta por um tempo, talvez haja algum truque para grep (não que eu não goste de awk – simplesmente saber mais é melhor).
  • A ação padrão é imprimir a linha correspondente para que a { print; } parte não ‘ seja realmente necessária ou útil aqui.

Resposta

Se patterns contiver um padrão por linha, você pode fazer algo assim:

 awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -  

Ou corresponde a substrings em vez de regulares expressões:

 awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -  

Para imprimir tudo em vez de nenhuma linha da entrada no caso patterns esteja vazio, substitua NR==FNR por FILENAME==ARGV[1] ou por ARGIND==1 em gawk.

Essas funções imprimem as linhas de STDIN que contêm cada string especificada como um argumento como uma substring. ga significa grep all e gai ignora maiúsculas e minúsculas.

 ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }  

Comentários

  • resposta nítida que aborda vários casos de uso e trabalhos (verificado em macos)

Resposta

grep pattern1 | grep pattern2 | ...

Eu gostaria de usar o grep único porque estou construindo argumentos dinamicamente , então tudo tem que caber em uma string

É realmente possível construir o pipeline dinamicamente (sem recorrer a eval):

 # Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont  

Provavelmente não é uma solução muito eficiente.

Comentários

  • Use chained-grep() ou function chained-grep, mas não function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Você pode descrever qual é o truque? Você pode adicioná-lo à resposta ( sem ” Editar: “, ” Atualização: ” ou semelhante) editando ?
  • Reformulou a resposta para tornar o truque mais claro (ex .: construir um pipeline de shell dinamicamente)

Resposta

git grep

Aqui está a sintaxe usando git grep combinando vários padrões usando expressões Booleanas :

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3 

O comando acima imprimirá linhas que correspondem a todos os padrões de uma vez.

--no-index Pesquise arquivos no diretório atual que não seja gerenciado pelo Git.

Verifique man git-grep para obter ajuda.

Veja também:

Para operação OU , consulte:

Comentários

  • Excelente resposta. Obrigado.

Resposta

Aqui está minha opinião, e isso funciona para palavras em várias linhas:

Use find . -type f seguido por quantos
-exec grep -q "first_word" {} \;
e a última palavra-chave com
-exec grep -l "nth_word" {} \;

-q silencioso / silencioso
-l mostrar arquivos com correspondências

O seguinte retorna uma lista de nomes de arquivos com as palavras “coelho” e “buraco” neles:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Comentários

  • Se você olhar com atenção, descobrirá que essa não é a funcionalidade que a pergunta está pedindo.

Resposta

ripgrep

Aqui está o exemplo usando rg :

rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt 

É uma das ferramentas de grep mais rápidas, pois é construído sobre Rust “s motor regex que usa autômatos finitos, SIMD e otimizações literais agressivas para tornar a pesquisa muito rápida.

Veja também a solicitação de recurso relacionado em GH-875 .

Resposta

Para encontrar todas as palavras (ou padrões), você pode executar grep em um for loop. A principal vantagem aqui é pesquisar em uma lista de expressões regulares .

Um exemplo real:

# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done 

Agora vamos executá-lo neste arquivo:

hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa 
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting! 

Comentários

  • Sua lógica está com defeito – eu perguntei por ALL, seu código funciona como OR operador, não AND. E aliás. Para isso (OR) é uma solução muito mais fácil dada na pergunta.
  • @greenoldman A lógica é simples: O for fará um loop em TODAS as palavras / padrões na lista, e se for encontrado no arquivo – irá imprimi-lo. Portanto, apenas remova o else se você não ‘ precisar de ação caso a palavra não seja encontrada.
  • Eu entendo sua lógica e também minha pergunta – eu estava perguntando sobre o operador AND, o que significa que o arquivo é apenas um resultado positivo se corresponder ao padrão A e ao padrão B e o padrão C e … AND No seu caso, o arquivo é um resultado positivo se for tches pattern A ou pattern B or … Você vê a diferença agora?
  • @greenoldman não tem certeza porque você acha que este loop não verifica a condição AND para todos os padrões? Então, ‘ editei minha resposta com um exemplo real: ele pesquisará no arquivo todas as regexs da lista e, na primeira que estiver faltando, sairá com erro.
  • Você tem isso bem na frente de seus olhos, você tem uma correspondência positiva logo após a primeira partida ser executada. Você deve ” coletar ” todos os resultados e calcular AND sobre eles. Então você deve reescrever o script para rodar em vários arquivos – então talvez você perceba que a pergunta já foi respondida e sua tentativa não trouxe nada para a mesa, desculpe.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *