Ошибка в проверке оболочки, когда строка является скобкой слева

Я был уверен в том, что цитирование строк всегда является хорошей практикой, чтобы избежать разбора синтаксического анализа.

Тогда я натолкнулся на это:

$ x='(' $ [ "$x" = '1' -a "$y" = '1' ] bash: [: `)' expected, found 1 

Попытка изолировать проблему, получив ту же ошибку:

 $ [ '(' = '1' -a '1' = '1' ] bash: [: `)' expected, found 1 

Я решил проблему следующим образом:

 [ "$x" = '1' ] && [ "$y" = '1' ] 

Еще мне нужно знать, что здесь происходит. Я верю, что вы, ребята, поможете мне в этом.

2 Solutions collect form web for “Ошибка в проверке оболочки, когда строка является скобкой слева”

Это очень непонятный краеугольный случай, когда можно было бы рассмотреть ошибку в том, как определяется тест [ встроенный; однако он соответствует поведению фактического [ двоичного кода, доступного во многих системах. Насколько я могу судить, это влияет только на определенные случаи и переменную, имеющую значение, которое соответствует [ operator like ( , ! , = , -e и т. Д.).

Позвольте мне объяснить, почему и как работать с ним в оболочках Bash и POSIX.


Объяснение:

Рассмотрим следующее:

 x="(" [ "$x" = "(" ] && echo yes || echo no 

Нет проблем; приведенное выше не дает ошибки и выводит yes . Так мы ожидаем, что работа будет работать. Вы можете изменить строку сравнения на '1' если хотите, и значение x , и она будет работать, как ожидалось.

Обратите внимание, что фактический /usr/bin/[ binary ведет себя одинаково. Если вы запускаете eg '/usr/bin/[' '(' = '(' ']' ошибки не возникает, потому что программа может обнаружить, что аргументы состоят из одной операции сравнения строк.

Ошибка возникает, когда мы и со вторым выражением. Неважно, что такое второе выражение, если оно действительно. Например,

 [ '1' = '1' ] && echo yes || echo no 

выводит yes и, очевидно, является допустимым выражением; но, если мы объединим два,

 [ "$x" = "(" -a '1' = '1' ] && echo yes || echo no 

Бэш отвергает выражение тогда и только тогда, когда 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" ] 

[ aka test видит:

  argc: 1 2 3 4 5 6 7 8 argv: ( = 1 -a 1 = 1 ] 

test принимает подвыражения в круглых скобках; поэтому он считает, что левая скобка открывает подвыражение и пытается ее разобрать; синтаксический анализатор видит = как первое в подвыражении и считает, что это неявный тест длины строки, поэтому он счастлив; затем подвыражение должно сопровождаться правой скобкой, и вместо этого парсер находит 1 вместо ) . И он жалуется.

Когда test имеет ровно три аргумента, а средний аргумент является одним из распознанных операторов, он применяет этот оператор к 1-му и 3-му аргументам без поиска подвыражений в круглых скобках.

Для полной информации смотрите man bash , найдите test expr .

Вывод: алгоритм синтаксического анализа, используемый при test является сложным. Используйте только простые выражения и используйте операторы оболочки ! , && и || объединить их.

  • Bash: параметр доступа, переданный последней команде
  • Как я могу профилировать сценарий оболочки?
  • Объединение зависимостей со сценариями оболочки
  • Локальная переменная как часть глобальной
  • Есть ли способ, чтобы функция в моем сценарии bash автоматически запускалась при любой ошибке команды?
  • Как узнать, какая программа может открыть данный файл?
  • Каков наиболее подходящий способ анализа значений из этого вывода?
  • Конкатенация строк с двумя строками
  • Есть ли простой способ изменить одну строку в большом количестве файлов?
  • Поиск файлов, содержащих общие слова
  • Как оболочка / init создает потоки stdio?
  • Linux и Unix - лучшая ОС в мире.