0 0 0 0


I am looking for a way to clean up the mess when my top-level script exits.

Especially if I want to use set -e, I wish the background process would die when the script exits.

Best Answer:

The trap 'kill 0' SIGINT SIGTERM EXIT solution described in @tokland's answer is really nice, but latest Bash crashes with a segmantation fault when using it. That's because Bash, starting from v. 4.3, allows trap recursion, which becomes infinite in this case:

  • shell process recieves SIGINT or SIGTERM or EXIT;
  • the signal gets trapped, executing kill 0, which sends SIGTERM to all processes in the group, including the shell itself;
  • go to 1 :)
  • This can be worked around by manually de-registering the trap:

    trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT

    The more fancy way, that allows to print the recieved signal and avoids "Terminated:" messages:

    #!/usr/bin/env bash
    trap_with_arg() { # from
      local func="$1"; shift
      for sig in "$@"; do
        trap "$func $sig" "$sig"
    stop() {
      trap - SIGINT EXIT
      printf 'n%sn' "recieved $1, killing children"
      kill -s SIGINT 0
    trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP
    { i=0; while (( ++i )); do sleep 0.5 && echo "a: $i"; done } &
    { i=0; while (( ++i )); do sleep 0.6 && echo "b: $i"; done } &
    while true; do read; done

    UPD: added minimal example; improved stop function to aviod de-trapping unnecessary signals and to hide "Terminated:" messages from the output. Thanks Trevor Boyd Smith for the suggestions!

    Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs