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

Set -e и короткие тесты

Когда я был новичком в сценариях оболочки, я использовал множество коротких тестов вместо операторов if, например false && true.

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

Самое интересное, что если я открою интерактивную оболочку и сделаю следующее:

set -e
false && true
echo $?

возвращает 1, но оболочка не умирает!

Я вижу, что я тратил слишком много строк кода. Любой может объяснить мне, как можно безопасно использовать set -e с короткими тестами, например. без script умирающих?

4b9b3361

Ответ 1

Что касается моей проблемы с неожиданным угасанием script, это связано с запуском этих коротких тестов в подоболочке или с помощью функции, а указанная функция возвращает значение, отличное от нуля:

Исходный пример:

$ set -e
$ false && true
$ echo $?
1

Использование подоболочки или функции:

$ set -e
$ (false && true)
<script died>

$ set -e
$ variable=$(false && true)
<script died>

$ set -e
$ foo()(false && true)
$ foo
<script died>

$ set -e
$ foo(){ false && true; }
$ foo
<script died>

Возможные решения:

$ set -e
$ (false && true ||:)
$ (false && true) ||:
$ (if false; then true; fi)

Ответ 2

Единая спецификация UNIX описывает эффект set -e как:

Если этот параметр включен, если простая команда не выполняется по любой из причин, перечисленных в Последствиях ошибок оболочки, или возвращает значение состояния выходa > 0 и не является частью составного списка через некоторое время, пока, или если ключевое слово и не является частью списка AND или OR и не является конвейером, которому предшествует! зарезервированное слово, то оболочка должна немедленно выйти.

Как вы видите, неудачная команда в списке AND не приведет к завершению работы оболочки.

Использование set -e

Запуск сценариев оболочки с set -e считается наилучшей практикой, так как обычно бывает более безопасным прервать script, если возникнет некоторая ошибка. Если команда может завершиться безвредно, я обычно добавляю к ней || true.

Вот простой пример:

#!/bin/sh
set -e

# [...]
# remove old backup files; do not fail if none exist
rm *~ *.bak || true

Ответ 3

Вам нужно завершить каждую команду, которая может завершиться неудачей с помощью ||, а список команд или команд будет равен 0. Используя ||, вы будете запускать вашу команду, если выражение перед оператором не будет равно 0. Ваша команда должна оценить до 0, чтобы не убить оболочку.

Пример:

set -e
false || true # silently ignore error

false || echo "Command failed, but exit status of echo is 0. Continuing..."

false || {                                                                      
  echo "Command failed. Continuing..."                                          
  # do something else                                                           
  false && true # all commands in the list need to be true                      
}

false && true не вызывает выход, потому что конечное выражение оценивается и оценивается равным 0. На странице bash man для set -e:

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

Только последняя команда, если выполняется в цепочке ||/&&, может вызвать выход.

Следующее выражение не будет устранено по причине выше.

true && false

но следующее не будет:

if true && false                                                                
then                                                                            
  true                                                                          
fi                   

из-за true && false является частью теста, следующего за if.

Ответ 4

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

Обратите внимание, что команды в Makefile обычно выполняются с помощью set -e, поэтому часто необходимо понять, как это работает.

Операторы && и || допускают аналогичный эффект с относительно небольшим беспорядком, но делают его явным. В частности, a && может быть помещен в конец строки так же, как `; '.