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