grep. Encontre vários padrões AND em qualquer ordem usando uma única condição

5

Existe alguma maneira de usar grep para procurar por entradas que correspondam a múltiplos padrões em qualquer ordem usando um único condidion?

Como mostrado em Como executar o grep com vários padrões AND ? para múltiplos padrões que eu posso usar

grep -e 'foo.*bar' -e 'bar.*foo'

mas eu tenho que escrever 2 condições aqui, 6 condições para 3 padrões e assim por diante ... Eu quero escrever uma condição única, se possível. Para encontrar padrões em qualquer ordem, você pode sugerir usar:

grep -e 'foo' | grep -e 'bar' # at least i do not retype patterns here

e isso funcionará, mas eu gostaria de ver a saída colorida e, nesse caso, apenas a barra será destacada.

Eu gostaria de escrever condição tão fácil quanto

awk '/foo/ && /bar/'

se for possível para grep (o awk não destaca os resultados e duvido que possa ser feito facilmente).

agrep provavelmente pode fazer o que eu quero, mas gostaria de saber se meu grep padrão (2.10-1) no Ubuntu 12.04 pode fazer isso.

    
por Derp 01.03.2015 / 13:47

4 respostas

3

Se a sua versão de grep for compatível com PCRE (o% GNU grep faz isso com a opção -P ou --perl-regexp ), você pode usar lookaheads para corresponder várias palavras em qualquer ordem:

grep -P '(?=.*?word1)(?=.*?word2)(?=.*?word3)^.*$'

Isso não destacará as palavras, no entanto. Lookaheads são asserções de comprimento zero, não fazem parte da sequência correspondente.

Acho que sua solução de tubulação deve funcionar para isso. Por padrão, grep apenas colore a saída quando estiver indo para um terminal, portanto, somente o último comando no pipeline será realçado, mas você pode substituir isso com --color=always .

grep --color=always foo | grep --color=always bar
    
por 01.03.2015 / 22:13
1

Uma opção complexa seria gerar todas as permutações dos padrões, fornecê-los a grep e esperar que o compilador regexp gere uma árvore de busca razoavelmente otimizada.

Mas mesmo com um pequeno número de padrões, digamos seis, as permutações seriam 6! ou 720. Isso cria uma linha de comando inábil.

Mas, vendo que você parece não ter brigas com cana grep exceto

and this will work but I would like to see colored output

então, contanto que :  * os padrões não se sobrepõem  * os padrões não contêm caracteres de controle de termo

uma solução aceitável seria canalizar vários grep s, cada um com um padrão, em ordem crescente de probabilidade, de modo a minimizar a carga.

Depois, para garantir que a colorização funcione, você precisará forçar grep em acreditando que sua saída padrão é um terminal usando faketerm ou caso contrário, ou se disponível (deve ser), você pode usar a opção --color=always :

cat file | grep --color=always pattern1 \
         | grep --color=always pattern2 \
         ...
         | grep --color=always patternN 

(Uma boa opção seria envolver o grep s em uma única string a ser executada por um subshell e gerar a string programaticamente usando, por exemplo, sed ).

    
por 04.03.2015 / 21:04
0

Você pode colorir a saída com sed

sed -n "/foo/{/bar/s/foo\|bar/\x1b[1;31m&\x1b[m/gp}"
    
por 01.03.2015 / 17:14
-3

Você pode fazer isso com um único regexp baseado em OR. Dado o conteúdo do arquivo:

This is my file
It has many words
There are also many chars

O comando grep a seguir destacaria 'my' e 'There' em um único argumento:

grep -P -e '(there|my)' testfile

Simplesmente separe cada padrão de expressão regular com | (canal) para indicar OR.

    
por 01.03.2015 / 15:37

Tags