Este é um caso de canto muito obscuro que pode ser considerado um bug em como o teste [
built-in é definido; no entanto, ele corresponde ao comportamento do binário real [
disponível em muitos sistemas. Até onde eu sei, isso afeta apenas certos casos e uma variável com um valor que corresponde a um operador [
como (
, !
, =
, -e
e assim por diante.
Deixe-me explicar por que e como contornar isso em shells Bash e POSIX.
Explicação:
Considere o seguinte:
x="("
[ "$x" = "(" ] && echo yes || echo no
Sem problemas; o acima não produz nenhum erro e gera yes
. É assim que esperamos que as coisas funcionem. Você pode alterar a string de comparação para '1'
, se desejar, e o valor de x
, e isso funcionará como esperado.
Observe que o real /usr/bin/[
binário se comporta da mesma maneira. Se você executar, por exemplo, '/usr/bin/[' '(' = '(' ']'
não há erro, porque o programa pode detectar que os argumentos consistem em uma única operação de comparação de strings.
O erro ocorre quando e com uma segunda expressão. Não importa qual seja a segunda expressão, desde que seja válida. Por exemplo,
[ '1' = '1' ] && echo yes || echo no
processa yes
e é obviamente uma expressão válida; mas, se combinarmos os dois,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash rejeita a expressão se e somente se x
for (
ou !
.
Se fôssemos executar o acima usando o programa [
real, ou seja,
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
o erro seria compreensível: como o shell faz as substituições de variável, o /usr/bin/[
binário recebe apenas os parâmetros (
=
(
-a
1
=
1
e a% final]
, compreensivelmente falha em analisar se os parênteses abertos iniciam uma sub-expressão ou não, havendo uma operação e envolvida. Claro, analisá-lo como duas comparações de seqüência de caracteres é possível, mas fazê-lo com avidez pode causar problemas quando aplicado a expressões adequadas com subexpressões entre parênteses.
O problema, na verdade, é que o shell [
interno se comporta da mesma maneira, como se expandisse o valor de x
antes de examinar a expressão.
(Essas ambigüidades e outras relacionadas à expansão de variáveis foram um grande motivo pelo qual o Bash implementou e agora recomenda usar as expressões [[ ... ]]
test).
A solução alternativa é trivial e, muitas vezes, é vista em scripts que usam mais antigos sh
shells. Você adiciona um caractere "seguro", geralmente x
, na frente das strings (ambos os valores sendo comparados), para garantir que a expressão seja reconhecida como uma comparação de string:
[ "x$x" = "x(" -a "x$y" = "x1" ]