12

I tried a following script:

#!/bin/bash
trap 'echo "touching a file" && touch $FILE' EXIT

foo1(){
        echo "foo1"
}
foo(){
        echo "foo"
        export FILE=${FILE:-/tmp/file1}
}
(foo1)
foo

The output for the above script was:

[root@usr1 my_tests]# ./test.sh
foo1
foo
touching a file

However I was expecting trap to be called on exit from foo1 as well, which is called in a subshell.

  • Is this expected?
  • Is trap inherited by a subshell?
  • If yes, then in what case is trap inherited by a subshell?
8

Trap handlers are never inherited by subshells. This is specified by POSIX:

When a subshell is entered, traps that are not being ignored are set to the default actions.

Note that ignored signals (trap '' SIGFOO) remain ignored in the subshell (and in external programs launched by the shell, too).

  • 2
    In bash you can set -E in order to have subshells inherit traps, but it is REALLY tricky to get right (at least in my experience). – dragon788 Sep 26 '18 at 2:11
  • I don't know if this works for all traps. I know it works for ERR – yosefrow Aug 21 at 11:38
4

trap is not propogated to subshells but some ways allow the subshell to report the traps of the parent shell and others don't. I did some tests on macos with bash.

GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap | cat # trap -- 'echo hello' EXIT
(trap) | cat # trap -- 'echo hello' EXIT
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # trap -- 'echo hello' EXIT

GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap > >(cat) # trap -- 'echo hello' EXIT
trap | cat # empty
(trap) | cat # empty
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # empty

This is good to know that trap_output="$(trap)" will work to capture trap output. I can't think of any other way to do it if that didn't work besides doing trap >trap_output_file to output it to a file (fifo won't work in bash 3.2.57) and then reading it back in with trap_output="$(<trap_output_file)"

fifo won't work in bash 3.2.57 because trap & is empty for bash 3.2.57 but not bash 4.4.12

GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# trap -- 'echo hello' EXIT

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell

GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# empty because trap >/tmp/fifo & is empty since it uses trap &

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell
2

trap definitions are not propagated to sub-shells.

Verify by:

trap "echo bla" 1 2 3"

(trap)

  • 1
    Many shells handle (trap) as a special case, so that the subshell can report (but not actually use) the traps of the parent shell. So that test isn't always reliable. – JigglyNaga May 12 '16 at 10:52
  • It works with the Bourne Shell and it's derivates: ksh88, bosh (schily Bourne Shell) and heirloom-sh. You are correct: ksh93 behaves differently. – schily May 12 '16 at 10:57
  • It doesn't work in bash, which the script in question uses. – JigglyNaga May 12 '16 at 11:01
  • Well, it works in bash: bash does not output anything if you call (trap). – schily May 12 '16 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.