Use Interrupt with Handle - for your Terminal Bash Env

While regular exit will not work from the child process that command_not_found_handle runs, interrupting the $$ process will.

Below is how the handle looks like that will halt the main when functions are NOT found.

#!/usr/bin/env bash

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

# 🏁 This handler will prevent 'not found commands' from continuing scripts in BASH 🏁
command_not_found_handle() {
  echo "command_not_found_handle: invoked with arguments=[$*]."
  echo "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 -$$
}
# Export this handler so it's available in:
# Child bash scripts that your script executes (e.g., ./some_script.sh)
#
# Without export: Only THIS script uses the handler
# With export: ALL child bash processes inherit and use this handler
export -f command_not_found_handle

main() {
  echo_with_pid "START"
  i_dont_exist hi1 hi2
  echo_with_pid "DONE"
}

main "${@}"

Output is below, where we can see that 'DONE' was prevented from running.

[$$=23624/23624] START
[$$=23624/23625] command_not_found_handle: invoked with arguments=[i_dont_exist hi1 hi2].
[$$=23624/23625] command_not_found_handle: Interrupting process group [23624].

Interrupting and CI/CD

Important: This interrupt-based approach works well for interactive terminal use, but should not be used in CI/CD pipelines (e.g., Jenkins (CI/CD)). The interrupt signal can terminate your CI/CD runner unexpectedly, causing what appears to be a crash without clear error messages.

Alternative for CI/CD: Instead of interrupting, have command_not_found_handle log errors to a file. Then check this log file either:

  • At the end of your script, or
  • Before executing the next step

This ensures errors are visible without risking runner termination.


Backlinks