Example Catching Not Even When There Is Failure Branch

Example where ERROR checking is up the chain

#!/usr/bin/env bash

command_not_found_handle() {
  # Exit
  echo_with_pid "command_not_found_handle: invoked with arguments=[$*]."
  echo_with_pid "command_not_found_handle: Interrupting process group [$$]."

  # Send an interrupt signal (SIGINT) to the entire process group
  # of the current shell session
  #
  # Breakdown:
  # - kill: command to send signals to processes
  # - -INT: the interrupt signal (same as Ctrl+C)
  # - -$$: negative PID targets the process group
  #   - $$: shell variable containing current shell's PID
  #   - negative sign: targets entire process group, not just single process
  kill -INT -$$
}

echo_with_pid(){
  echo "[\$\$=$$/$BASHPID] $*"
}

foo2() {
  echo_with_pid "foo2-enter"
  i_dont_exist
  echo_with_pid "foo2-exit"
}

foo1() {
  echo_with_pid "foo1-enter"
  foo2
  echo_with_pid "foo1-exit"
}

main() {
  echo_with_pid "START"
  foo1
  echo_with_pid "DONE"
}

if main; then
  echo "Main succeeded"
else 
  echo "Main failed"
fi

As we would like, the handler get's called which allows to intercept.

❯/tmp/scratch.sh
[$$=39900/39900] START
[$$=39900/39900] foo1-enter
[$$=39900/39900] foo2-enter
[$$=39900/39901] command_not_found_handle: invoked with arguments=[i_dont_exist].
[$$=39900/39901] command_not_found_handle: Interrupting process group [39900].

For reference set -e flag gets confused by above setup and does not intercept, if some function up the chain has success or error branch. (See: ❌ Checking for failure/success, even up the chain prevents 'set -e' from triggering.❌)

The handler even works when we have non-zero branch right on the non existing function

#!/usr/bin/env bash

command_not_found_handle() {
  echo_with_pid "command_not_found_handle: invoked with arguments=[$*]."
  echo_with_pid "command_not_found_handle: Interrupting process group [$$]."
  kill -INT -$$
}

echo_with_pid(){
  echo "[\$\$=$$/$BASHPID] $*"
}

main() {
  echo_with_pid "START"
  i_dont_exist b-1 b-2 || echo "If it doesnt exist"
  echo_with_pid "DONE"
}

main "${@}" || exit 1

Output:

❯/tmp/scratch.sh
[$$=42511/42511] START
[$$=42511/42512] command_not_found_handle: invoked with arguments=[i_dont_exist b-1 b-2].
[$$=42511/42512] command_not_found_handle: Interrupting process group [42511].

Backlinks