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 umagrep
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 agrep -E
, em oposição aos BRE ‘ s quegrep
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()
oufunction chained-grep
, mas nãofunction 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:
- Como podemos e grep para corresponder string1 E string2?
- Verifique se todas as strings ou regexes múltiplas existem em um arquivo .
Para operação OU , consulte:
- Como faço para executar grep para múltiplos padrões com padrão tendo uma barra vertical?
- Grep: como adicionar um ” OU ” condição?
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 comoOR
operador, nãoAND
. 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.
foo
e linhas que contenhambar
” consulte usando grep para vários padrões de pesquisa