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" ]