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