Grep pesquisando duas palavras em uma linha

36

Estou tentando encontrar uma maneira de filtrar uma linha com a palavra "limão" e "arroz". Eu sei como encontrar "limão" ou "arroz", mas não os dois. Eles não precisam estar ao lado do outro, apenas uma na mesma linha de texto.

    
por Sebastian 26.02.2015 / 22:13

6 respostas

49

"Ambos na mesma linha" significa "'arroz' seguido por caracteres aleatórios seguidos por 'limão' ou o contrário".

Na regex, que é rice.*lemon ou lemon.*rice . Você pode combinar isso usando um | :

grep -E 'rice.*lemon|lemon.*rice' some_file

Se você quiser usar o regex normal em vez dos estendidos normais ( -E ), precisará de uma barra invertida antes do | :

grep 'rice.*lemon\|lemon.*rice' some_file

Para mais palavras que ficam um pouco mais demoradas e geralmente é mais fácil usar várias chamadas de grep , por exemplo:

grep rice some_file | grep lemon | grep chicken
    
por Florian Diesch 26.02.2015 / 22:29
22

Você pode canalizar a saída do primeiro comando grep para outro comando grep e que corresponderia a ambos os padrões. Então, você pode fazer algo como:

grep <first_pattern> <file_name> | grep <second_pattern>

ou

cat <file_name> | grep <first_pattern> | grep <second_pattern>

Exemplo:

Vamos adicionar alguns conteúdos ao nosso arquivo:

$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt

O que o arquivo contém:

$ cat test_grep.txt 
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.

Agora, vamos ver o que queremos:

$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.

Só obtemos as linhas nas quais os dois padrões correspondem. Você pode estender isso e canalizar a saída para outro comando grep para mais combinações "AND".

    
por Aditya 26.02.2015 / 22:31
16

Embora a pergunta seja "grep", achei que seria útil postar uma solução simples "awk":

awk '/lemon/ && /rice/'

Isso pode ser facilmente estendido com mais palavras ou outras expressões booleanas além de 'e'.

    
por David B. 27.02.2015 / 04:49
10

Outra ideia para encontrar as correspondências em qualquer ordem é usar:

grep com a opção -P (Perl-Compatibility) e expressão positiva antecipada (?=(regex)) :

grep -P '(?=.*?lemon)(?=.*?rice)' infile

ou você pode usar abaixo, em vez disso:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • O .*? significa corresponder a todos os caracteres . que ocorreram zero ou mais vezes * , enquanto eles são opcionais seguidos por um padrão ( rice ou lemon ). O ? torna tudo opcional antes dele (significa zero ou uma vez em que tudo corresponde a .* )

(?=pattern) : Lookahead positivo: o constructo lookahead positivo é um par de parênteses, com o parêntese de abertura seguido por um ponto de interrogação e um sinal de igual.

Portanto, isso retornará todas as linhas contendo lemon e rice em ordem aleatória. Além disso, isso evitará usar | s e dobrou grep s.

Links externos:
Tópicos Avançados do Grep
Lookahead Positivo - GREP para Designers

    
por αғsнιη 27.02.2015 / 00:05
2
grep -e foo -e goo

Irá retornar correspondências para foo ou goo

    
por netskink 24.07.2017 / 16:46
0

Aqui está um script para automatizar a solução de tubulação grep:

#!/bin/bash

# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}

grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n  ]]
then
grep -i "" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}

grepand "$@"
    
por Jeff 03.02.2017 / 02:21