Why does `type which` say that `which is hashed`?
You likely have a long PATH set and, to find an executable, the shell needs to search the path. To avoid that time consuming process every time that you want to run a program, the shell may keep a list of programs that it has already found. That list is called a "hash." When the shell says that which
is hashed, it means that it has already done the PATH search and found which
and saved its location in the hash.
man bash
explains it as follows:
Bash uses a hash table to remember the full pathnames of executable files (see hash under SHELL BUILTIN COMMANDS below). A full search of the directories in PATH is performed only if the command is not found in the hash table.
While the hash normally speeds up shell operations, there is one case where it causes problems. If you update your system and, as a result, some executable moves to a new location, the shell may get confused. The solution is to run hash -r
which causes the shell to forget all the hashed locations and search the PATH from scratch.
Why are some executables missing from the hash?
An executable is not placed in the hash until after you execute at least once. Observe:
$ type python
python is /usr/bin/python
$ python --version
Python 2.7.3
$ type python
python is hashed (/usr/bin/python)
python
is hashed only after it has been executed.
How to examine what is in bash's hash
The contents of the hash are available in the bash
array BASH_CMDS
. You can see what is in it with the command declare -p BASH_CMDS
. When a new shell or subshell is opened, the hash is empty. Commands are added one by one as they are used. From a newly opened shell, observe:
$ declare -p BASH_CMDS
declare -A BASH_CMDS='()'
$ which which
/bin/which
$ declare -p BASH_CMDS
declare -A BASH_CMDS='([which]="/bin/which" )'
$ python --version
Python 2.7.3
$ declare -p BASH_CMDS
declare -A BASH_CMDS='([which]="/bin/which" [python]="/usr/bin/python" )'