TIL: Bash caches the paths of commands
.. using hash
.
Thanks to https://news.ycombinator.com/item?id=43840285:
Fun fact: if you've ever had bash (or another shell) complain that a file doesn't exist, even though it's on
$PATH
, check if it's been cached byhash
. If the file is moved elsewhere on$PATH
and bash has the old path cached, you will get an ENOENT. The entire cache can be invalidated withhash -r
.
Try it yourself
Let's try to reproduce the "file doesn't exist" error. Run a shell in a docker container, and echo the PATH:
> docker run --rm -it ubuntu
root@47d19e31a63a:/# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Let's look at what programs are in /usr/local/bin
and /usr/bin`:
root@47d19e31a63a:/# ls /usr/local/bin
root@47d19e31a63a:/# ls /usr/bin
...
Nothing in /usr/local/bin
, but loads of stuff in /usr/bin
. Let's try running uptime
:
root@47d19e31a63a:/# uptime
14:26:10 up 1 min, 0 user, load average: 1.13, 0.55, 0.36
Now let's try moving uptime
to /usr/local/bin
, and run it again. Since it's in the PATH
, we should be able to discover it, but we expect this to fail because we know the entry is cached.
root@47d19e31a63a:/# mv /usr/bin/uptime /usr/local/bin/uptime
root@47d19e31a63a:/# uptime
bash: /usr/bin/uptime: No such file or directory
root@47d19e31a63a:/# /usr/local/bin/uptime
14:27:16 up 2 min, 0 user, load average: 0.66, 0.60, 0.41
We managed to reproduce the error! Let's look at the hash
table now:
root@47d19e31a63a:/# hash
hits command
1 /usr/bin/mv
1 /usr/bin/uptime
2 /usr/bin/ls
Interestingly, echo
is not cached, even though echo
is also a program.
Let's try clearing the cache, and running uptime
again.
root@47d19e31a63a:/# hash -r
root@47d19e31a63a:/# uptime
14:32:38 up 25 min, 0 user, load average: 0.24, 0.41, 0.37
root@47d19e31a63a:/# which uptime
/usr/local/bin/uptime