Подтвердить что ты не робот

Почему эта ошибка Bash script отсутствует?

Здесь мой Bash script:

#!/bin/bash -e

if [ == "" ]; then
  echo "BAD"
  exit 1
fi

echo "OK"

И вот вывод:

./test.sh: line 3: [: ==: unary operator expected
OK

Код возврата равен 0.

В строке 3 очевидна синтаксическая ошибка. Вместо того, чтобы поднять синтаксическую ошибку и отказаться от запуска script, как-то script просто запускается и сообщает о синтаксической ошибке во время выполнения. Флаг -e не защитил меня от этого - очевидно, синтаксическая ошибка в выражении if представляет собой ложное условие, а не причину немедленно выйти из программы. НО, каким-то образом Bash проанализировал весь блок if ... fi, поэтому после игнорирования плохой строки выполнение каким-то образом возобновляется не на следующей синтаксически правильной строке, а после окончания блока?

У меня есть два вопроса:

  • Что происходит?
  • Как я могу защитить себя от этого поведения в будущем?
4b9b3361

Ответ 1

  • if запускает команду [ и просто проверяет свой код возврата. Bash не знает и не заботится о синтаксисе команды [.

    Вы можете поместить там какую-нибудь другую команду, а Bash все равно ничего не узнает о ее конкретном синтаксисе.

  • Приходят на ум две вещи:

    • Использование [[ вместо [: Bash знает и заботится о его синтаксисе.

    • Использование ShellCheck 1; онлайн, вручную или в пределах вашего любимого редактора.

Оба if и -e имеют дело с кодами выхода: если он отличен от нуля if, вы не войдете в блок then, а -e выйдет. Вы не можете действительно иметь оба эти поведения сразу. (Ну, кажется, что [ выходит с разными кодами для ложных результатов (1) и синтаксических ошибок (2), поэтому возможно "обнаружить ошибки синтаксиса".


1 Или какой-то другой инструмент, но единственное, что я знаю. Предложения приветствуются.

Ответ 2

Здесь нет синтаксической ошибки оболочки.

У вас есть ошибка в аргументах команды [/builtin.

Причина set -e здесь не помогает, потому что явно не то, что он должен делать. set -e стал бы полностью бесполезным, если бы у вас не было операторов if в вашем коде с ним. Подумайте об этом.

Если вы посмотрите в спецификации POSIX, то что означает флаг -e/errexit:

-e

Когда эта опция включена, когда какая-либо команда не работает (по любой из причин, перечисленных в Последствия ошибок оболочки или возвращая статус выхода больше нуля) оболочка немедленно выйдет со следующими исключениями:

  • Сбой какой-либо отдельной команды в конвейере с несколькими командами не должен вызывать оболочку. Следует учитывать только провал самого трубопровода.

  • Параметр -e игнорируется при выполнении составного списка, следующего за , а, до, , если или elif зарезервированное слово, конвейер, начинающийся с зарезервированного слова !, или любая команда списка AND-OR, отличного от последнего.

  • Если статус выхода составной команды, отличной от команды подоболочки, был результатом отказа, тогда как -e был проигнорирован, тогда -e не будет применяться к этой команде.

Это требование применяется к среде оболочки и каждой среде подсетей отдельно. Например, в:

set -e; (false; echo one) | cat; echo two

См. пункт 2 там? Это ваша ситуация.

Причина, по которой оболочка продолжает выполняться, возвращается к "не синтаксической ошибке оболочки". У вас есть командная ошибка. Команда [/builtin попыталась проанализировать свои аргументы и не удалось. Затем он возвратил код возврата ошибки. if поймал это, пропустил его тело и вернул true (согласно документированному поведению if, когда условия не возвращают true). Итак, оболочка script продолжалась нормально.

Однако, как я указал в своем комментарии, если вы использовали [[ (который представляет собой bash -ism и конструкцию языка), ваш script имел бы синтаксическую ошибку и немедленно выходил бы эта строка (по крайней мере, в моих тестах).

Ответ 3

На странице bash man

-e

Выйти немедленно, если конвейер (который может состоять из простой простой команды), команда подголовника, заключенная в круглые скобки, или одна из команд, выполняемых как часть списка команд, заключенного в фигурные скобки (см. SHELL GRAMMAR выше), завершается с помощью ненулевой статус. Оболочка не выходит из, если неудавшаяся команда является частью списка команд сразу после некоторого времени или до ключевого слова части теста, следующего за зарезервированными словами if или elif часть любой команды, выполненной в && или ││, за исключением команды, следующей за окончательным && или ││, любая команда в конвейере, но последняя, ​​или если возвращаемое значение команды инвертируется с помощью!. Ловушка ERR, если установлена, выполняется до выхода оболочки. Этот параметр применим к среде оболочки и каждой среде подсетей отдельно (см. ОБЩИЕ УСЛОВИЯ ОКРУЖАЮЩЕЙ СРЕДЫ выше) и может вызывать подоболочки для выхода до выполнения всех команд в подоболочке.

Акцент на мой.

Ответ 4

Во-первых, это не синтаксическая ошибка. Вы просто предоставляете плохие аргументы команде [.

Во-вторых, статус выхода команды из списка, следующего за ключевым словом if, игнорируется для параметра -e.