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


38

Eu tenho um arquivo que tem "então" e "lá".

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 procurar 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)

Respostas:


54

Você precisa colocar a expressão entre aspas. O erro que você está recebendo é resultado da interpretação do bash (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ê tem que escapar do |, (e ). Observe que usamos aspas simples aqui. O Bash trata barras invertidas especialmente entre aspas duplas.

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

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

$ grep 'then\|there' x.x

Seria necessário para algo como isto:

$ grep 'the\(n\|re\)' x.x

3
Veja também grep $'then\nthere'e grep -e then -e there. Observe que isso \|não é padrão nos BREs. O resto é. Bash trata barras invertidas especialmente dentro de aspas duplas somente antes ", $, \ , `e de nova linha.
Stéphane Chazelas

1
Qual é o propósito x.x?
alex

7

Apenas um adendo rápido, a maioria dos sabores possui 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


2

O material documentado em EXPRESSÕES REGULARES na (ou pelo menos minha) página de manual é na verdade para regexps estendidos ;

O grep compreende três versões diferentes da sintaxe da expressão regular: “básico”, “estendido” e “perl”. No GNU grep, não há diferença na funcionalidade disponível entre as sintaxes básica e estendida. Em outras implementações, expressões regulares básicas são menos poderosas. A descrição a seguir se aplica a expressões regulares estendidas; as diferenças para expressões regulares básicas são resumidas posteriormente.

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

grep "(then|there)" x.x

Porque (na página de manual novamente):

Expressões regulares básicas versus estendidas

Nas expressões regulares básicas, os meta-caracteres?, +, {, |, (, E) perdem seu significado especial; em vez disso, use as versões com barra invertida \ ?, +, {, \ |, (, e).

Então você também pode usar:

grep "then\|there" x.x

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


0

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

Além das excelentes soluções acima, pensei em tentar dar uma dica sobre como o bash analisa e interpreta as instruçõ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 planejado.


Nota: As linhas de script do shell são usadas diretamente. As linhas de entrada digitadas são primeiro expandidas no histórico.

Cada linha do bash é primeiro tokenizada ou, em outras palavras, dividida no que é chamado de tokens . (A tokenização ocorre antes de todas as outras expansões, incluindo chaves, 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 meta-caracteres 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 apenas esses 10 produzem os tokens iniciais.

No entanto, como esses meta-caracteres às vezes também devem ser usados ​​dentro de um token, é preciso haver uma maneira de remover seu significado especial. Isso é chamado de escape. O escape é feito citando uma sequência de um ou mais caracteres (ou seja 'xx..', "xx..") ou prefixando um caractere individual com uma barra invertida (ou seja \x). (É um pouco mais complicado que isso porque as aspas também precisam ser citadas e porque aspas duplas não citam tudo, mas essa simplificação será válida por enquanto.)

Não confunda citações bash com a idéia de citar uma sequência de texto, como em outros idiomas. O que há entre aspas no bash não são cadeias, mas seções da linha de entrada que possuem metacaracteres escapadas para que não delimitem os tokens.

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

Os meta-caracteres não escapados restantes se tornam separadores de token.

Por exemplo,

$ echo "x"'y'\g
xyg

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

$ echo x\; echo y
x; echo y

No primeiro exemplo, existem dois tokens produzidos por um delimitador de espaço: echoe xyz.

Da mesma forma no segundo exemplo.

No terceiro exemplo, o ponto e vírgula é escapado, de forma que há 4 fichas fabricadas 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 echonão é executado.


A coisa importante a lembrar é que o bash primeiro procura por personagens que escapam ( ', "e \), e em seguida, olha para delimitadores de meta-caracteres unescaped, nessa ordem.

Se não escapou, esses 10 caracteres especiais servem como tokendelimitadores. Alguns deles também têm significado adicional, mas, acima de tudo, são delimitadores de token.


O que o grep espera

No exemplo acima grep precisa destes sinais, grep, string, filename.

A primeira tentativa da pergunta foi:

$ grep (então | lá) xx

Neste caso (, )e |são caracteres meta unescaped e assim servem para dividir a entrada para estes símbolos: grep, (, then, |, there, ), e x.x. grep quer ver grep, then|theree x.x.

A segunda tentativa da pergunta foi:

grep "(então | lá)" xx

Este tokenizes em grep, (then|there), x.x. Você pode ver isso se você trocar grep por eco:

eco "(então | lá)" xx
(então | lá) xx

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.