Я изучаю содержимое этого файла preinst, который скрипт выполняет перед тем, как этот пакет будет распакован из файла архива Debian (.deb).
Скрипт имеет следующий код:
#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
if [ -d /usr/share/MyApplicationName ]; then
echo "MyApplicationName is just installed"
return 1
fi
rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section
Мой первый запрос о строке:
set -e
Я думаю, что остальная часть сценария довольно проста: он проверяет, выполняет ли менеджер пакетов Debian / Ubuntu операцию установки. Если это так, он проверяет, было ли мое приложение только что установлено в системе. Если это так, скрипт выводит сообщение «MyApplicationName только что установлено» и завершается ( return 1
что означает «ошибка», не так ли?).
Если пользователь просит систему пакетов Debian / Ubuntu установить мой пакет, сценарий также удаляет две директории.
Это правильно или я что-то упустил?
man set
set +e
Ответы:
От
help set
:Но некоторые считают это плохой практикой (часто задаваемые вопросы по bash и irc freenode #bash часто задаваемые вопросы). Рекомендуется использовать:
запустить
do_something
функцию при возникновении ошибок.Смотрите http://mywiki.wooledge.org/BashFAQ/105
источник
trap 'exit' ERR
ERR
Ловушка не наследуется оболочки функций, поэтому если у вас есть функции,set -o errtrace
илиset -E
позволит вам просто установить ловушку раз и применять его во всем мире.trap 'exit' ERR
делать что - нибудь отличается отset -e
?set -e
останавливает выполнение скрипта, если в команде или конвейере произошла ошибка - что противоположно поведению оболочки по умолчанию, которое заключается в игнорировании ошибок в скриптах. Введитеhelp set
в терминал, чтобы увидеть документацию для этой встроенной команды.источник
set -o pipefail
которую можно использовать для распространения ошибок, чтобы возвращаемое значение команды конвейера отличалось от нуля, если одна из предыдущих команд вышла с ненулевым статусом.-o pipefail
означает только то, что статус выхода первой ненулевой (то есть ошибочной в-o errexit
терминах) команды конвейера распространяется до конца. Остальные команды в конвейере по- прежнему выполняются , даже сset -o errexit
. Например:,echo success | cat - <(echo piping); echo continues
гдеecho success
представляет успешную, но ошибочную команду, напечатаетsuccess
,piping
иcontinues
, ноfalse | cat - <(echo piping); echo continues
, сfalse
представлением команды, теперь с ошибкой молчащей, все равно будет печататьpiping
перед выходом.Согласно bash - в руководстве Set Builtin , если
-e
/errexit
установлено, оболочка немедленно завершается, если конвейер, состоящий из одной простой команды , списка или составной команды, возвращает ненулевой статус.По умолчанию состояние выхода конвейера является состоянием выхода последней команды в конвейере, если эта
pipefail
опция не включена (по умолчанию она отключена).Если это так, состояние возврата конвейера последней (самой правой) команды для выхода с ненулевым статусом или ноль, если все команды завершаются успешно.
Если вы хотите выполнить что-то при выходе, попробуйте определить
trap
, например:где
onexit
ваша функция, чтобы сделать что-то при выходе, как показано ниже, которая печатает простую трассировку стека :Существует аналогичная опция
-E
/,errtrace
которая вместо этого будет ловить ERR, например:Примеры
Пример нулевого статуса:
Пример ненулевого статуса:
Примеры отрицательного статуса:
Тест с
pipefail
отключением:Тест с
pipefail
включенным:источник
Я нашел этот пост, пытаясь выяснить, каков был статус выхода для сценария, который был прерван из-за
set -e
. Ответ не казался мне очевидным; отсюда и этот ответ. По сути,set -e
прерывает выполнение команды (например, сценарий оболочки) и возвращает код состояния завершения команды, которая завершилась неудачей (т. Е. Внутренний сценарий, а не внешний сценарий) .Например, предположим, у меня есть сценарий оболочки
outer-test.sh
:Код для
inner-test.sh
:Когда я запускаю
outer-script.sh
из командной строки, мой внешний скрипт завершается с кодом выхода внутреннего скрипта:источник
Я полагаю, что цель сценария - быстро провалиться.
Чтобы проверить это самостоятельно, просто введите
set -e
в командной строке bash. Теперь попробуйте запуститьls
. Вы получите список каталогов. Теперь введитеlsd
. Эта команда не распознается и возвращает код ошибки, поэтому ваша подсказка bash закроется (из-заset -e
).Теперь, чтобы понять это в контексте «скрипта», используйте этот простой скрипт:
Если вы запустите его как есть, вы получите список каталогов из
ls
последней строки. Если вы раскомментируетеset -e
и запускаете снова, вы не увидите список каталогов, так как bash прекращает обработку, когда обнаруживает ошибку отlsd
.источник
Это старый вопрос, но ни один из ответов здесь не обсуждает использование
set -e
akaset -o errexit
в сценариях обработки пакетов Debian. Использование этой опции обязательно в этих сценариях согласно политике Debian; очевидно, что цель состоит в том, чтобы избежать любой возможности необработанного условия ошибки.На практике это означает, что вы должны понимать, при каких условиях выполняемые вами команды могут возвращать ошибку, и явно обрабатывать каждую из этих ошибок.
Обычными ошибками являются, например,
diff
(возвращает ошибку при наличии разницы) иgrep
(возвращает ошибку при отсутствии совпадения). Вы можете избежать ошибок с явной обработкой:(Обратите также внимание на то, как мы позаботимся о том, чтобы имя текущего скрипта включалось в сообщение и записывали диагностические сообщения в стандартную ошибку вместо стандартного вывода.)
Если никакая явная обработка не является действительно необходимой или полезной, явно ничего не делайте:
(Использование команды оболочки
:
no-op немного неясно, но довольно часто встречается.)Просто чтобы повторить,
это сокращение для
то есть мы явно говорим, что
other
должен быть запущен тогда и только тогда, когдаsomething
произойдет сбой. Стенограммаif
(и другие операторы управления потоком оболочки, такие какwhile
,until
) также является допустимым способом обработки ошибки (в самом деле, если бы это было не так, сценарии оболочки с такими параметрамиset -e
никогда не могли бы содержать операторы управления потоком!)А также, чтобы быть в явном виде, в отсутствие такого обработчика, это
set -e
может привести к немедленному отказу всего сценария с ошибкой, если будетdiff
найдено различие или еслиgrep
не найдено совпадение.С другой стороны, некоторые команды не выдают состояние выхода из ошибки, когда вы этого хотите. Обычно проблемными являются команды
find
(состояние выхода не отражает, были ли файлы фактически найдены) иsed
(состояние выхода не показывает, получил ли скрипт какой-либо ввод или действительно выполнил какие-либо команды успешно). В некоторых случаях простой защитой является передача по команде, которая кричит, если нет вывода:Следует отметить, что состояние выхода конвейера является состоянием выхода последней команды в этом конвейере. Таким образом, вышеприведенные команды на самом деле полностью маскируют статус
find
иsed
и только сообщают вам,grep
наконец-то, успешно ли это выполнено .(Bash, конечно, имеет
set -o pipefail
; но сценарии пакета Debian не могут использовать функции Bash. Политика твердо диктует использование POSIXsh
для этих сценариев, хотя это не всегда имело место.)Во многих ситуациях это то, на что следует обращать особое внимание при кодировании с защитой. Иногда вам нужно, например, просмотреть временный файл, чтобы увидеть, успешно ли завершилась команда, создавшая этот вывод, даже если в противном случае идиома и удобство заставили бы вас использовать конвейер оболочки.
источник
источник