Quero encontrar todas as linhas em vários arquivos que correspondam a um dos dois padrões. Tentei encontrar os padrões que estou procurando digitando
grep (foo|bar) *.txt
mas o shell interpreta o |
como um pipe e reclama quando bar
não é um executável.
Como posso grep para vários padrões no mesmo conjunto de arquivos?
Respostas:
Primeiro, você precisa proteger o padrão da expansão pelo shell. A maneira mais fácil de fazer isso é colocar aspas simples. Aspas simples impedem a expansão de qualquer coisa entre elas (incluindo barras invertidas); a única coisa que você não pode fazer é ter aspas simples no padrão.
Se você precisar de uma única citação, poderá escrevê-la como
'\''
(final da string literal, literal literal, open string literal).Segundo, o grep suporta duas sintaxes para padrões. A sintaxe padrão antiga ( expressões regulares básicas ) não suporta o
|
operador alternation ( ), embora algumas versões a tenham como uma extensão, mas gravadas com uma barra invertida.A maneira portátil é usar a sintaxe mais recente, expressões regulares estendidas . Você precisa passar a
-E
opçãogrep
para selecioná-lo. No Linux, você também pode digitar emegrep
vez degrep -E
(em outras unidades, você pode transformar isso em um alias).Outra possibilidade quando você está apenas procurando por um dos vários padrões (em vez de criar um padrão complexo usando disjunção) é passar vários padrões para
grep
. Você pode fazer isso precedendo cada padrão com a-e
opçãofonte
fgrep
ougrep -F
, para pequenos padrões, a diferença será insignificante, mas à medida que eles se prolongam, os benefícios começam a aparecer ...grep -F
um benefício real de desempenho depende da implementação grep: alguns deles aplicam o mesmo algoritmo de qualquer maneira, de modo que-F
faz diferença apenas no tempo gasto na análise do padrão e não na pesquisa de tempo. O GNU grep não é mais rápido-F
, por exemplo (ele também possui um bug que tornagrep -F
mais lento os códigos de idioma multibyte - o mesmo padrão constante com elegrep
é significativamente mais rápido!). Por outro lado, o BusyBox grep se beneficia muito-F
com arquivos grandes.egrep
é anteriorgrep -E
. Não é específico do GNU (certamente não tem nada a ver com Linux). Na verdade, você ainda encontrará sistemas como o Solaris nos quais o padrãogrep
ainda não é compatível-E
.ou
citando seletivamente a página de manual do gnu-grep:
(...)
No começo, não li mais, então não reconheci as diferenças sutis:
Sempre usei egrep e desnecessariamente parens, porque aprendi com exemplos. Agora eu aprendi algo novo. :)
fonte
Como o TC1 disse,
-F
parece ser uma opção utilizável:fonte
Primeiro, você precisa usar aspas para caracteres especiais. Segundo, mesmo assim,
grep
não entenderá a alternância diretamente; você precisaria usaregrep
, ou (grep
apenas com GNU )grep -E
.(Os parênteses são desnecessários, a menos que a alternância faça parte de uma regex maior.)
fonte
grep -E
é mais padrão do queegrep
.Se você não precisa de expressões regulares, é muito mais rápido usar
fgrep
ougrep -F
com vários parâmetros -e, como este:fgrep
(alternativamentegrep -F
) é muito mais rápido que o grep normal, porque procura por seqüências fixas em vez de expressões regulares.fonte
fgrep
está obsoleto.Você pode tentar o comando abaixo para obter o resultado:
fonte
Uma maneira barata e alegre de grep para vários padrões:
fonte
-f
opção grep pega um arquivo com vários padrões. Em vez de criar um arquivo temporário (que você pode esquecer de apagar depois), basta usar a substituição do processo do shell:grep -f <(echo foo; echo bar) *.txt
Pipe (
|
) é um caractere de shell especial, portanto, ele precisa ser escapado (\|
) ou citado de acordo com o manual (man bash
):Veja: Quais caracteres precisam ser escapados no Bash?
Aqui estão alguns exemplos (usando ferramentas ainda não mencionadas):
Usando
ripgrep
:rg "foo|bar" *.txt
rg -e foo -e bar *.txt
Usando
git grep
:git grep --no-index -e foo --or -e bar
Nota: Ele também suporta expressões booleanas como
--and
,--or
e--not
.Para operação AND por linha, consulte: Como executar o grep com vários padrões AND?
Para operação AND por arquivo, consulte: Como verificar se existem várias seqüências de caracteres ou expressões regulares em um arquivo?
fonte
Eu tinha logs de acesso em que as datas eram estupidamente formatadas: [30 / jun / 2013: 08: 00: 45 +0200]
Mas eu precisava exibi-lo como: 30 / jun / 2013 08:00:45
O problema é que, usando "OR" na minha declaração grep, eu estava recebendo as duas expressões de correspondência em duas linhas separadas.
Aqui está a solução:
fonte
TL; DR: se você quiser fazer mais coisas depois de corresponder a um dos vários padrões, coloque-os como em
\(pattern1\|pattern2\)
exemplo: eu quero encontrar todos os lugares onde uma variável que contém o nome 'date' é definida como uma String ou int. (por exemplo, "int cronDate =" ou "String textFormattedDateStamp ="):
Com
grep -E
, você não precisa escapar dos parênteses ou do tubo, ou seja,grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='
fonte
Isso funciona para mim
fonte
Existem várias maneiras de fazer isso.
grep 'foo\|bar' *.txt
egrep 'foo|bar' *.txt
find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'
A 3ª e a 4ª opção cumprem apenas nos arquivos e evitam que os diretórios tenham
.txt
seus nomes.Portanto, conforme seu caso de uso, você pode usar qualquer uma das opções mencionadas acima.
Obrigado!!
fonte
para adicionar à resposta do @ geekosaur , se você tiver vários padrões que também contenham guias e espaço, use o seguinte comando
onde
[[:blank:]]
é a classe de caracteres RE que representa um espaço ou um caractere de tabulaçãofonte