Since Bash 4.0, if the search for a command is unsuccessful, the shell searches for a function called command_not_found_handle
. If it doesn't exist, Bash prints a message like this and exits with status 127:
$ foo
-bash: foo: command not found
$ echo $?
127
If it does exist, it is called with the command and its arguments as arguments, so if you have something like
command_not_found_handle () {
echo "It's my handle!"
echo "Arguments: $@"
}
in your .bashrc
, Bash will react like this:
$ foo bar
It's my handle!
Arguments: foo bar
Most systems have something much more sophisticated in place, though. My Ubuntu, for example, has this in /etc/bash.bashrc
:
# if the command-not-found package is installed, use it
if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
function command_not_found_handle {
# check because c-n-f could've been removed in the meantime
if [ -x /usr/lib/command-not-found ]; then
/usr/lib/command-not-found -- "$1"
return $?
elif [ -x /usr/share/command-not-found/command-not-found ]; then
/usr/share/command-not-found/command-not-found -- "$1"
return $?
else
printf "%s: command not found\n" "$1" >&2
return 127
fi
}
fi
and this is sourced from /etc/profile
. /usr/lib/command-not-found
is a Python script that uses some more Python (CommandNotFound
) to basically look up packages that are named like the unknown command, or sound similar:
$ sl
The program 'sl' is currently not installed. You can install it by typing:
sudo apt install sl
$ sedd
No command 'sedd' found, did you mean:
Command 'sed' from package 'sed' (main)
Command 'seedd' from package 'bit-babbler' (universe)
Command 'send' from package 'nmh' (universe)
Command 'send' from package 'mailutils-mh' (universe)
sedd: command not found
So if you want simple customization, you can provide your own command_not_found_handle
, and if you want to customize the existing system, you can modify the Python scripts.
But, as mentioned, this requires Bash 4.0 or higher.