Este é um caso de canto muito obscuro, que pode ser considerado um bug na [definição do teste interno; no entanto, ele corresponde ao comportamento do [binário real disponível em muitos sistemas. Tanto quanto eu posso dizer, só afecta certos casos e uma variável com um valor que corresponde a um [operador como (, !, =, -e, e assim por diante.
Deixe-me explicar o porquê e como contornar isso nos shells Bash e POSIX.
Explicação:
Considere o seguinte:
x="("
[ "$x" = "(" ] && echo yes || echo no
Sem problemas; o acima não gera erro e gera resultados yes. É assim que esperamos que as coisas funcionem. Você pode alterar a sequência de comparação para '1'se desejar e o valor de x, e funcionará conforme o esperado.
Observe que o /usr/bin/[binário real 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 operação de comparação de string única.
O bug ocorre quando nós e com uma segunda expressão. Não importa qual é a segunda expressão, desde que válida. Por exemplo,
[ '1' = '1' ] && echo yes || echo no
saídas yese é obviamente uma expressão válida; mas, se combinarmos os dois,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
O Bash rejeita a expressão se e somente se xé (ou !.
Se executarmos o procedimento acima usando o [programa atual , 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áveis, o /usr/bin/[binário recebe apenas parâmetros ( = ( -a 1 = 1e a finalização ], é compreensível que ele não analise se os parênteses abertos iniciam ou não uma subexpressão, havendo uma operação e . Certamente, é possível analisá-lo como duas comparações de strings, mas fazê-lo com avidez pode causar problemas quando aplicado a expressões apropriadas 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 xantes de examinar a expressão.
(Essas ambiguidades, e outras relacionadas à expansão de variáveis, foram um grande motivo pelo qual o Bash foi implementado e agora recomenda o uso das [[ ... ]]expressões de teste.)
A solução alternativa é trivial e geralmente é vista em scripts usando shshells mais antigos . 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 strings:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]