Como posso grep para isto ou aquilo (2 coisas) em um arquivo?

27

Eu tenho um arquivo que tem "then" e "there".

Eu posso

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

e eu posso

$ grep "there " x.x
If there is no blob none some will be created

Como posso pesquisar os dois em uma operação? Eu tentei

$ grep (then|there) x.x

-bash: erro de sintaxe próximo ao token inesperado '('

e

grep "(then|there)" x.x
durrantm.../code
# (Nothing)
    
por Michael Durrant 14.07.2013 / 18:01

4 respostas

41

Você precisa colocar a expressão entre aspas. O erro que você está recebendo é resultado de interpretar o ( como um caractere especial.

Além disso, você precisa dizer ao grep para usar expressões regulares estendidas.

$ grep -E '(then|there)' x.x

Sem expressões regulares estendidas, você precisa escapar dos | , ( e ) . Observe que usamos aspas simples aqui. Bash trata as barras invertidas entre aspas duplas especialmente.

$ grep '\(then\|there\)' x.x

O agrupamento não é necessário neste caso.

$ grep 'then\|there' x.x

Seria necessário algo assim:

$ grep 'the\(n\|re\)' x.x
    
por 14.07.2013 / 18:10
7

Apenas um adendo rápido, a maioria dos sabores tem um comando chamado egrep que é apenas grep com -E. Eu pessoalmente gosto muito melhor de digitar

egrep "i(Pod|Pad|Phone)" access.log

Do que usar grep -E

    
por 14.07.2013 / 19:30
2

O material documentado em EXPRESSÕES REGULARES na (ou pelo menos na minha) página do manual é, na verdade, para expressões estendidas ;

grep understands three different versions of regular expression syntax: “basic,” “extended” and “perl.” In GNU grep, there is no difference in available functionality between basic and extended syntaxes. In other implementations, basic regular expressions are less powerful. The following description applies to extended regular expressions; differences for basic regular expressions are summarized afterwards.

Mas o grep não os usa por padrão - você precisa da opção -E :

grep "(then|there)" x.x

Porque (da página man novamente):

Basic vs Extended Regular Expressions

In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, +, {, \|, (, and ).

Você também pode usar:

grep "then\|there" x.x

Como os parênteses são supérfluos neste caso.

    
por 14.07.2013 / 18:11
0

A simplicidade elegante do Bash parece se perder em sua enorme página de manual.

Além das excelentes soluções acima, pensei em tentar fornecer uma folha de dicas sobre como o bash analisa e interpreta as declarações . Em seguida, usando este roteiro, analisarei os exemplos apresentados pelo questionador para ajudá-lo a entender melhor por que eles não funcionam como pretendido.

Observação: as linhas de script shell são usadas diretamente. As linhas de entrada digitadas são primeiro expandidas pelo histórico.

Cada linha bash é primeiro tokenizada ou, em outras palavras, dividida em tokens . (A tokenização ocorre antes de todas as outras expansões, incluindo chave, til, parâmetro, comando, aritmética, processo, divisão de palavras e expansão de nome de arquivo.)

Um token aqui significa uma parte da linha de entrada separada (delimitada) por um desses metacaracteres especiais:

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

O Bash usa muitos outros caracteres especiais, mas somente esses 10 produzem os tokens iniciais.

No entanto, como esses meta-caracteres também devem ser usados em um token, é necessário que haja uma maneira de eliminar seu significado especial. Isso é chamado de escape. O escape é feito citando uma cadeia de um ou mais caracteres (por exemplo, 'xx..' , "xx.." ) ou prefixando um caractere individual com uma barra invertida (ou seja, \x ). (É um pouco mais complicado do que isso, porque as aspas também precisam ser citadas, e porque aspas duplas não citam tudo, mas essa simplificação fará por enquanto.)

Não confunda o bash com a idéia de citar uma string de texto, como em outros idiomas. O que está entre aspas no bash não são strings, mas sim seções da linha de entrada que possuem meta-caracteres escapados para que eles não delimitem tokens.

Note que há uma diferença importante entre ' e " , mas isso é para outro dia.

Os metacaracteres restantes sem escape tornam-se separadores de tokens.

Por exemplo,

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

No primeiro exemplo, há dois tokens produzidos por um delimitador de espaço: echo e xyz .

Da mesma forma no segundo exemplo.

No terceiro exemplo, o ponto-e-vírgula é escapado, portanto, há quatro tokens produzidos por um delimitador de espaço, echo , x; , echo e y . O primeiro token é então executado como o comando e recebe os próximos três tokens como entrada. Observe que o segundo echo não é executado.

O importante é lembrar que o bash primeiro procura por caracteres de escape ( ' , " e \ ) e, em seguida, procura por delimitadores de meta-caracteres sem escape, nessa ordem.

Se não tiver escapado, esses 10 caracteres especiais serão usados como delimitadores token . Alguns deles também têm significado adicional, mas acima de tudo, são delimitadores de tokens.

O que o grep espera

No exemplo acima, o grep precisa desses tokens, grep , string , filename .

A primeira tentativa da pergunta foi:

$ grep (then|there) x.x

Nesse caso, ( , ) e | são metacaracteres sem escape e servem para dividir a entrada nesses tokens: grep , ( , then , | , there , ) e x.x . grep quer ver grep , then|there e x.x .

A segunda tentativa da pergunta foi:

grep "(then|there)" x.x

Isso é tokenizado em grep , (then|there) , x.x . Você pode ver isso se você trocar grep por echo:

echo "(then|there)" x.x
(then|there) x.x

    
por 30.12.2017 / 01:41