web-dev-qa-db-fra.com

Comment intercepter ERR lors de l'utilisation de «set -e» dans Bash

J'ai un script simple:

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

function func(){
    ls /root/
}

func

Je voudrais piéger ERR si mon script échoue (car il sera ici b/c, je n'ai pas les autorisations pour regarder dans/root). Cependant, lorsque vous utilisez set -e il n'est pas piégé. Sans pour autant set -e ERR est piégé.

Selon la page de manuel de bash, pour set -e:

... Un piège sur ERR, s'il est défini, est exécuté avant la fermeture du shell. ...

Pourquoi mon piège n'est-il pas exécuté? De la page de manuel, il semble que cela devrait.

23

réponse de chepner est la meilleure solution : si vous voulez combiner set -e (pareil que: set -o errexit) avec un piège ERR, utilisez également set -o errtrace (pareil que: set -E) .

En bref: utilisez set -eE au lieu de simplement 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 dit à propos de set -o errtrace/set -E:

S'il est défini, tout piège sur ERR est hérité par les fonctions Shell, les substitutions de commandes et les commandes exécutées dans un environnement de sous-shell. Le piège ERR n'est normalement pas hérité dans de tels cas.

Je crois que ce qui se passe:

  • Sans-e: La commande ls échoue à l'intérieur de votre fonction et, en raison de sa dernière commande, la fonction signale le code de sortie non nul de ls à l'appelant, la portée de votre script de niveau supérieur . Dans cette étendue, l'interruption ERR est en vigueur et elle est invoquée (mais notez que l'exécution continuera, sauf si vous appelez explicitement exit à partir de l'interruption ).

  • Avec-e (mais sans -E): La commande ls échoue à l'intérieur de votre fonction, et parce que set -e est en vigueur, Bash instantanément se termine, directement depuis la portée de la fonction - et puisqu'il n'y a pas de ERR trap en vigueur ici (car il n'a pas été hérité de la portée parent), votre trap n'est pas appelé.

Bien que la page man ne soit pas incorrecte, je conviens que ce comportement n'est pas exactement évident - vous devez le déduire.

36
mklement0

Vous devez utiliser set -o errtrace pour que la fonction hérite du piège.

9
chepner

Remplacez ERR par EXIT et cela fonctionnera.

La syntaxe de la commande trap est: trap [COMMANDS] [SIGNALS]

Pour plus d'informations, veuillez lire http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html

4
Ritesh