Usando o sinal de estrela no grep

87

Estou tentando pesquisar a substring "abc" em um arquivo específico no linux / bash

Então eu faço:

grep '*abc*' myFile

Não retorna nada.

Mas se eu fizer:

grep 'abc' myFile

Ele retorna as correspondências corretamente.

Agora, isso não é um problema para mim. Mas e se eu quiser pesquisar uma string mais complexa, diga

*abc * def *

Como eu faria isso usando grep?

Saobi
fonte
3
O grep em si não suporta curingas na maioria das plataformas. Você deve usar egrep para usar curingas. Os shells têm uma sintaxe diferente. "*" no shell é <qualquer string>. Em egrep, é um operador que diz "0 para muitos da entidade anterior". No grep, é apenas um caractere regular.
PanCrit 01 de
@PanCrit: *significa a mesma coisa em grep e egrep: é um quantificador que significa zero ou mais do átomo anterior. Esse é um conceito completamente diferente dos curingas usados ​​pelo shell.
Alan Moore

Respostas:

123

O asterisco é apenas um operador de repetição , mas você precisa dizer o que você repete. /*abc*/corresponde a uma string contendo ab e zero ou mais c's (porque o segundo * está no c; o primeiro não tem sentido porque não há nada para repetir). Se você quiser corresponder a qualquer coisa, você precisa dizer .*- o ponto significa qualquer caractere ( dentro de certas diretrizes ). Se você deseja corresponder apenas a abc, basta dizer grep 'abc' myFile. Para uma correspondência mais complexa, você precisa usar .*- grep 'abc.*def' myFileirá corresponder a uma string que contém abc seguido por def com algo opcionalmente no meio.

Atualização com base em um comentário:

*em uma expressão regular não é exatamente igual a * no console. No console, * é parte de uma construção glob e apenas atua como um curinga (por exemplo ls *.log, listará todos os arquivos que terminam em .log). No entanto, em expressões regulares, * é um modificador, o que significa que se aplica apenas ao caractere ou grupo que o precede. Se você quiser * em expressões regulares para atuar como um curinga, você precisa usar .*como mencionado anteriormente - o ponto é um caractere curinga, e a estrela, ao modificar o ponto, significa encontrar um ou mais pontos; ou seja, encontre um ou mais de qualquer personagem.

Daniel Vandersluis
fonte
1
Acho que o questionador está confuso sobre a diferença entre curingas de shell e expressões regulares. Também suspeito que a expressão mais complicada seria: grep 'abc. * Def' (pelo menos um espaço presente - possivelmente dois, como escrevi).
Jonathan Leffler
1
Na verdade, o questionador parece não entender que 'abc' não é a mesma coisa que '^ abc $' :-D
Massa
1
Sim, fiquei confuso entre glob e expressões regulares completas. Eu uso o * sem um ponto para significar correspondência com qualquer coisa na casca.
Saobi 01 de
1
grep *significa "0 ou mais", e grep é ganancioso por padrão. Note que no grep básicas de expressões regulares os metacaracteres ?, +, {, |, (, e )perdem seu significado especial. Mais informações: grep
regexps
24

O caractere ponto significa corresponder a qualquer caractere, portanto, .*significa zero ou mais ocorrências de qualquer caractere. Você provavelmente pretende usar em .*vez de apenas *.

smcameron
fonte
Ponto é um metacaractere que aceita qualquer caractere, exceto novas linhas .
Abhishek Kamal
12

O "signo" só tem significado se houver algo na frente dele. Se não houver a ferramenta (grep neste caso), pode tratar isso apenas como um erro. Por exemplo:

'*xyz'    is meaningless
'a*xyz'   means zero or more occurrences of 'a' followed by xyz
Jonathan Leffler
fonte
5
O * não é sem sentido; simplesmente não tem seu significado usual (de repetição), mas significa "Eu sou uma estrela". Ele corresponderia a uma linha contendo uma estrela seguida por x, y e z.
Jonathan Leffler
2
@Jonathan Depende da ferramenta.
7

Use grep -P - que ativa o suporte para expressões regulares de estilo Perl.

grep -P "abc.*def" myfile
Artem Russakovskii
fonte
6

A expressão que você tentou, como aquelas que funcionam na linha de comando do shell no Linux, por exemplo, é chamada de " glob ". Expressões Glob não são expressões regulares completas , que é o que grep usa para especificar strings a serem procuradas. Aqui está um post (antigo, pequeno) sobre as diferenças. As expressões glob (como em "ls *") são interpretadas pelo próprio shell.

É possível traduzir de globs para REs, mas normalmente você precisa fazer isso em sua cabeça.

desanuviar
fonte
1
É apenas um glob se for analisado pelo shell. Como ele está preservando a string de pesquisa entre aspas simples, o shell deixa a string intacta e a passa intacta em argv para grep.
Conspicuous Compiler
4

Você não está usando expressões regulares, então sua variante grep de escolha deve ser fgrep, que se comportará como você espera.

Andrew Beals
fonte
2
fgrepagora está obsoleto, grep -fdeve ser usado em seu lugar.
Prometeu de
1
Isso é "grep -F". O bom e velho fgrep pode estar "obsoleto", mas eles não vão tirá-lo enquanto eu ainda estiver vivo.
Andrew Beals,
1

Esta pode ser a resposta que você está procurando:

grep abc MyFile | grep def

A única coisa é ... ele irá mostrar linhas onde "def" está antes OU depois de "abc"

Charles Duke
fonte
1

Isso funcionou para mim:

grep ". * $ {expr}" - com aspas duplas, precedidas do ponto. Onde "expr" é qualquer string de que você precisa no final da linha.

Grep unix padrão sem opções adicionais.

acesso concedido
fonte
0

'*' funciona como um modificador para o item anterior. Portanto, 'abc * def' procura por 'ab' seguido por 0 ou mais 'c's seguidos por' def '.

O que você provavelmente deseja é 'abc. * Def', que procura por 'abc' seguido por qualquer número de caracteres, seguido por 'def'.

Compilador Conspícuo
fonte