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