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 yes
e é 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
=
1
e 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 x
antes 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 sh
shells 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' ]]