У меня есть несколько настроенных bash-скриптов, которые в основном используют
#!/bin/bash
но я регулярно сталкиваюсь с некоторыми, которые выглядят как
#!/bin/bash -e
#!/bin/bash -x
#!/bin/bash -ex
и так далее.
Может ли кто-нибудь объяснить значение и преимущества этих опций шебанга и применимы ли они к другим шебангам?
решение1
Если скрипт /path/to/foo
начинается с #!/bin/bash
, то выполнение /path/to/foo arg1 arg2
эквивалентно выполнению /bin/bash /path/too/foo arg1 arg2
. Если строка shebang — #!/bin/bash -ex
, то это эквивалентно выполнению /bin/bash -ex /path/too/foo arg1 arg2
. Эта функция управляется ядром.
Обратите внимание, что в строке shebang можно переносить только один аргумент: некоторые UNIX-системы (например, Linux) принимают только один аргумент, поэтому это #!/bin/bash -e -x
приведет к тому, что bash получит единственный пятисимвольный аргумент -e -x
(синтаксическая ошибка) вместо двух аргументов -e
и -x
.
Для оболочки Bourne sh
и производных оболочек, таких как POSIX sh, bash, ksh и zsh:
-e
означает, что если какая-либо команда завершится неудачно (на что указывает возврат ненулевого статуса), скрипт будет немедленно завершен.-x
заставляет оболочку выводить трассировку выполнения.
Другие программы могут понимать эти параметры, но с другим значением.
решение2
Это параметры, передаваемые для bash
просмотра help set
дополнительной информации, в данном случае:
-x Print commands and their arguments as they are executed.
-e Exit immediately if a command exits with a non-zero status.
решение3
Я бы хотел упомянуть еще более лучшую (в смысле более портативную) альтернативу:
#!/usr/bin/env bash
В примере выше используется env
для поиска bash
исполняемого файла, который не всегда находится в /bin/bash
. Старые #!/bin/bash
скрипты не работают наNixOS, например.
Если вы используете env
, как показано выше, вы не можете предоставить аргумент, такой как -e
to bash
(насколько я знаю). Но вы можете сделать это вместо этого:
#!/usr/bin/env bash
set -e
решение4
Запуск скрипта с помощью или эквивалентный запуск имеет тот же эффект, что и вставка внутрь скрипта сразу после его строки.#! /path/to/bash -option
bash -option /path/to/script
set -option
#!
set -x
по сути, предназначен только для отладки; в обычном режиме его оставлять включенным нежелательно.
Эффект set -e
намного сложнее, чем предполагает руководство. Более точное описание примерно такое:
После вызова
set -e
, еслинепроверенныйкоманда завершается с ненулевым статусом, это приведет к завершению работы оболочки с этим статусом завершения.
Я говорюточнеепотому что это все еще довольно расплывчато: список ситуаций, когда команда считаетсяпроверенозагадочно и трудно предсказуемо. Точные правила различаются в зависимости от оболочки и даже меняются между версиями одной и той же оболочки.
set -e
делаетнетзаставляют Bash завершать работу в ответ на ненулевой статус завершения любой команды:
- между
if
/elif
иthen
; или - между
while
/until
иdo
; или - следующий
!
; или - за которым следует
||
или&&
или&
(хотя&
соответствующееwait
илиfg
может не сработать); или - за которым следует
|
, если неset -o pipefail
действует; или - внутри
$( ... )
, когда используется как часть команды (не просто назначения и/или перенаправления, что означает, чтоfoo=$( bar )
в случае сбоя произойдет сбойbar
, ноlocal foo=$( bar )
не произойдет); или - в составе составной команды, где применяется вышеизложенное; или
- внутри функции оболочки, вызываемой из любого места, где применимо вышеизложенное.
Эффекты составных команд и функций оболочки являются рекурсивными.
Поскольку сама оболочка выходит с ненулевым статусом, эффект может распространяться за пределы подоболочки.
Исключение !
применяется даже в случае игнорирования инвертированного статуса выхода.
И наоборот, set -e
триггеры накаждый второйненулевой статус, независимо от того, означает ли он "fail" или просто "false". Например, ((x++))
будет иметь ненулевой статус выхода "fail", когда x
изначально равен 0.
Поскольку это действительно запутанная ситуация, существует мнение, что этого set -e
следует избегать в пользу явной проверки всех команд.
Или, если вы все же хотите использовать set -e
, не забудьте написать !
перед всеми ((arithmetic))
группами.