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: echo
e 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 echo
nã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 token
delimitadores. 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|there
e 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