Это очень непонятный угловой случай, который можно рассматривать как ошибку в определении [встроенного теста ; однако он соответствует поведению действительного [двоичного файла, доступного во многих системах. Насколько я могу судить, это затрагивает только некоторые случаи , и переменную , имеющую значение , которое соответствует [оператору , как (, !, =, -eи так далее.
Позвольте мне объяснить, почему и как обойти это в оболочках Bash и POSIX.
Объяснение:
Учтите следующее:
x="("
[ "$x" = "(" ] && echo yes || echo no
Нет проблем; вышеупомянутое не дает ошибки, и выводит yes. Вот как мы ожидаем, что вещи будут работать. Вы можете изменить строку сравнения на, '1'если хотите, и значение x, и оно будет работать как положено.
Обратите внимание, что действительный /usr/bin/[двоичный файл ведет себя так же. Если вы запустите, например, '/usr/bin/[' '(' = '(' ']'ошибки нет, потому что программа может обнаружить, что аргументы состоят из одной операции сравнения строк.
Ошибка возникает, когда мы и со вторым выражением. Неважно, что является вторым выражением, если оно действительно. Например,
[ '1' = '1' ] && echo yes || echo no
выводит yes, и, очевидно, является допустимым выражением; но, если мы объединим два,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash отклоняет выражение тогда и только тогда, когда xесть (или !.
Если бы мы запустили вышеизложенное, используя реальную [программу
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
ошибка понятна: поскольку оболочка выполняет подстановку переменных, /usr/bin/[двоичный файл принимает только параметры ( = ( -a 1 = 1и завершение ], понятно, что он не может разобрать, начинаются ли подвыражения с открытых скобок или нет, если задействована операция and . Конечно, синтаксический анализ в виде двух строковых сравнений возможен, но жадное выполнение этого может привести к проблемам при применении к правильным выражениям с вложенными выражениями в скобках.
Проблема, действительно, заключается в том, что [встроенная оболочка ведет себя так же, как если бы она расширила значение xперед проверкой выражения.
(Эти неоднозначности и другие, связанные с расширением переменных, были основной причиной, по которой Bash реализовал и теперь рекомендует [[ ... ]]вместо этого использовать тестовые выражения.)
Обходной путь тривиален и часто встречается в сценариях с использованием более старых shоболочек. Вы добавляете «безопасный» символ, часто xперед строками (сравниваются оба значения), чтобы выражение распознавалось как сравнение строк:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]