Почему этот скрипт 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 /% Значок co_de% вы видите это описание:

  

-e

     

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

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

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

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

  6.   

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

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

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

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

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

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

На странице пользователя bash

  

-e

     

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

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

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

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

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

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