Как захватить ERR при использовании 'set -e' в Bash

У меня есть простой script:

#!/bin/bash
set -e
trap "echo BOO!" ERR 

function func(){
    ls /root/
}

func

Я хотел бы захватить ERR, если мой script терпит неудачу (так как он будет здесь b/c У меня нет прав на просмотр в /root ). Однако при использовании set -e он не попадает в ловушку. Без set -e ERR попадает в ловушку.

Согласно странице bash man, для set -e:

... Ловушка ERR, если установлена, выполняется до выхода оболочки....

Почему моя ловушка не выполняется? С man-страницы кажется, что это должно быть.

Ответ 1

Ответ chepner - лучшее решение: если вы хотите объединить set -e (аналогично: set -o errexit) с ловушкой ERR, также используйте set -o errtrace (аналогично: set -e).

Вкратце: используйте set -eE вместо только что set -e:

#!/bin/bash

set -eE  # same as: 'set -o errexit -o errtrace'
trap 'echo BOO!' ERR 

function func(){
  ls /root/
}

# Thanks to -E / -o errtrace, this still triggers the trap, 
# even though the failure occurs *inside the function*.
func 

man bash говорит о set -o errtrace/set -e:

Если установлено, любая ловушка в ERR наследуется функциями оболочки, подстановками команд и командами, выполняемыми в среде подоболочки. Ловушка ERR обычно не наследуется в таких случаях.

То, что я считаю, происходит:

  • Без -e: команда ls не выполняется внутри вашей функции, и, поскольку она является последней командой в функции, функция сообщает вызывающему код ls отличный от нуля, вашей области действия сценария верхнего уровня. В этой области действует прерывание ERR, и оно вызывается (но учтите, что выполнение будет продолжено, если вы явно не вызовете exit из прерывания).

  • С -e (но без -e): команда ls не выполняется внутри вашей функции, и, поскольку set -e, Bash мгновенно завершает работу, прямо из области действия функции, и поскольку там нет действующей ловушки ERR (поскольку он не был унаследован от родительской области), ваша ловушка не вызывается.

Хотя man страница не является неправильной, я согласен, что это поведение не совсем очевидно - вы должны сделать вывод.

Ответ 2

Вам нужно использовать set -o errtrace, чтобы функция наследовала ловушку.

Ответ 3

Замените ERR на EXIT, и он будет работать.

Синтаксис команды trap: trap [COMMANDS] [SIGNALS]

Для получения дополнительной информации, пожалуйста, прочитайте http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html