Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] Run ZERR trap also when there was a Zsh error



In order to ease debugging, one can use the ZERR trap to catch any command that returns a non-zero exit status (outside of a conditional _expression_) and display additional information on the context where it happened. A common source of errors in scripts are typos in variable names. These can be turned into Zsh errors thanks to the -u option. Unfortunately, trap execution is disabled in the presence of Zsh errors. Thus, an undefined variable won't run the ZERR trap and one may still be stuck with an utterly unhelpful message like "(anon):1: foo: parameter not set".

There doesn't seem to be any fundamental reason to never run traps in the presence of Zsh errors. In fact there are already exceptions. For instance, the EXIT trap is run even if Zsh errors are present. The patch below replicates this logic for the ZERR trap.

- Run ZERR trap also when there was a Zsh error

Philippe

diff --git a/Src/exec.c b/Src/exec.c
index 47d70b5a9..60075f254 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1598,7 +1598,10 @@ sublist_done:
 	if (!this_noerrexit && !donetrap && !this_donetrap) {
 	    if (sigtrapped[SIGZERR] && lastval &&
 		!(noerrexit & NOERREXIT_EXIT)) {
+		int eflag = errflag;
+		errflag = 0;
 		dotrap(SIGZERR);
+		errflag = eflag;
 		donetrap = 1;
 	    }
 	    if (lastval) {
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 87b7fd1f7..9924e4f96 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -361,6 +361,81 @@
 >trap
 >Working 0
 
+  ok() {   true         } # All good
+  ko() {   false        } # Just a non-zero status
+  KO() { { : $KO } 2>&1 } # A Zsh error
+  fn() {
+    echo "$1"
+    set -u;
+    case $1 in
+      *-TRAP-ok) TRAPZERR() { echo "ok 1"; ok; echo "ok 2" };;
+      *-trap-ok) trap        'echo "ok 1"; ok; echo "ok 2"' ZERR;;
+      *-TRAP-KO) TRAPZERR() { echo "ok 1"; KO; echo "KO 2" };;
+      *-trap-KO) trap        'echo "ok 1"; KO; echo "KO 2"' ZERR;;
+      *        ) echo "Unrecognized id: $1";
+    esac
+    case $1 in
+      ko-*-*) ko; echo "ok 3";;
+      KO-*-*) KO; echo "KO 3";;
+      *     ) echo "Unrecognized id: $1";
+    esac
+  }
+  (fn ko-TRAP-ok; echo "ok 4"); echo "\$?=$?"
+  (fn ko-trap-ok; echo "ok 4"); echo "\$?=$?"
+  (fn ko-TRAP-KO; echo "ok 4"); echo "\$?=$?"
+  (fn ko-trap-KO; echo "ok 4"); echo "\$?=$?"
+  (fn KO-TRAP-ok; echo "KO 4"); echo "\$?=$?"
+  (fn KO-trap-ok; echo "KO 4"); echo "\$?=$?"
+  (fn KO-TRAP-KO; echo "KO 4"); echo "\$?=$?"
+  (fn KO-trap-KO; echo "KO 4"); echo "\$?=$?"
+0:DDD
+>ko-TRAP-ok
+>ok 1
+>ok 2
+>ok 3
+>ok 4
+>$?=0
+>ko-trap-ok
+>ok 1
+>ok 2
+>ok 3
+>ok 4
+>$?=0
+>ko-TRAP-KO
+>ok 1
+>KO: KO: parameter not set
+F:Shouldn't the error in the trap prevent any further execution?
+>ok 3
+>ok 4
+>$?=0
+>ko-trap-KO
+>ok 1
+>KO: KO: parameter not set
+F:Shouldn't the error in the trap prevent any further execution?
+>ok 3
+>ok 4
+>$?=0
+>KO-TRAP-ok
+>KO: KO: parameter not set
+>ok 1
+>ok 2
+>$?=1
+>KO-trap-ok
+>KO: KO: parameter not set
+>ok 1
+>ok 2
+>$?=1
+>KO-TRAP-KO
+>KO: KO: parameter not set
+>ok 1
+>KO: KO: parameter not set
+>$?=1
+>KO-trap-KO
+>KO: KO: parameter not set
+>ok 1
+>KO: KO: parameter not set
+>$?=1
+
    { trap 'echo This subshell is exiting' EXIT; } | cat
 0: EXIT trap set in current shell at left of pipeline
 >This subshell is exiting


Messages sorted by: Reverse Date, Date, Thread, Author