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