Почему не возникает ошибка этого сценария Bash?

17

Вот мой скрипт на Bash:

#!/bin/bash -e

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

echo "OK"

А вот и вывод:

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

Код возврата - 0.

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

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

  1. Что происходит?
  2. Как я могу защитить себя от этого поведения в будущем?
задан qntm 08.12.2015 в 14:36
источник
  • 1, если запускает команду [ и просто проверяет свой код возврата. Bash не знает и не заботится о синтаксисе для команды [. (Вы можете поместить там какую-то другую команду, и Bash все равно ничего не узнает о ее синтаксисе.) 2 Используйте [[вместо [и shellcheck.net. –  Biffen 08.12.2015 в 14:39
  • Несмотря на то, что [и [[встроены в bash, bash поддерживает поведение, как если бы оно не было, даже из режима совместимости с POSIX. Вещи «встроены» для удобства и скорости, а не для изменения логики языка. –  ghoti 08.12.2015 в 14:43
  • В любом случае, это не синтаксическая ошибка. –  class stacker 08.12.2015 в 14:43
  • Право. Как указано, вещь, которая бросает ошибку на фиктивный синтаксис, [[встроена или нет). Он делает это, когда доходит до этого. (Выполнение этого раньше было бы нечетным. Сценарии оболочки не были предварительно скомпилированы.) Может ли это случиться как часть if, а не [? ... Наверное, но это будет лишняя, очень конкретная логика в синтаксическом анализаторе оболочки и т. Д. –  Etan Reisner 08.12.2015 в 14:50
  • @KarolyHorvath Оболочка абсолютно обрабатывает ошибки синтаксиса if-related. Попробуйте, если, затем echo foo; fi или если затем echo foo; например, fi. (Хотя я дам, что это не так, если что-то делать точно.) Проблема здесь не в ошибке с if или списком команд. Это ошибка с командой [command / builtin. –  Etan Reisner 08.12.2015 в 14:52
Показать остальные комментарии

4 ответа

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

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

  2. На ум приходят две вещи:

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

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

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

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

    
ответ дан Biffen 08.12.2015 в 15:09
  • Вы серьезно говорите мне, что есть команда под названием [? –  qntm 08.12.2015 в 18:31
  • @qntm Это альтернативная форма тестовой команды. –  gla3dr 08.12.2015 в 18:36
  • Я обветшал. Любые другие не-буквенно-цифровые команды, о которых я должен знать? Является ; специальная команда тоже? Как насчет «На этом этапе я поверил бы чему угодно. –  qntm 08.12.2015 в 18:40
  • @qntm нет, но: и. также являются встроенными командами (хотя - в отличие от [- POSIX определяет их как специальные) –  Mathias R. Jessen 08.12.2015 в 19:33
  • @qntm Некоторые символы пунктуации имеют специальные значения для оболочки. ; и "do. Вы абсолютно можете сделать / usr / bin / ;, но чтобы вызвать его, вы должны были бы избежать., поэтому, вероятно, этого не поймать. [просто не имеет особого значения, оставляя его честная игра для тех, кто решил, что если [$ condition] читает лучше, чем если условие $ test. –  Blacklight Shining 08.12.2015 в 23:10
9

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

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

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

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

-e

When this option is on, when any command fails (for any of the reasons listed in Consequences of Shell Errors or by returning an exit status greater than zero), the shell immediately shall exit with the following exceptions:

  1. The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered.

  2. The -e setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last.

  3. If the exit status of a compound command other than a subshell command was the result of a failure while -e was being ignored, then -e shall not apply to this command.

This requirement applies to the shell environment and each subshell environment separately. For example, in:

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

Видите пункт два там? Это твоя ситуация.

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

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

    
ответ дан Etan Reisner 08.12.2015 в 15:08
2

Со страницы руководства bash

-e

Exit immediately if a pipeline (which may consist of a single simple command), a subshell command enclosed in parentheses, or one of the commands executed as part of a command list enclosed by braces (see SHELL GRAMMAR above) exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or ││ list except the command following the final && or ││, any command in a pipeline but the last, or if the command's return value is being inverted with !. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.

Акцент мой.

    
ответ дан 123 08.12.2015 в 15:08
1

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

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

    
ответ дан chepner 08.12.2015 в 15:08