hash -r to clear a cache after updating PATH.@b0rk I tested this some and was wrong. Setting PATH seems to clear the cache for you. But if you remove a binary from PATH then you need to run hash -r for it to find a different binary in PATH.
bash-5.1$ echo "echo haha" >| /tmp/cat; chmod +x /tmp/cat
bash-5.1$ type cat
cat is /usr/bin/cat
bash-5.1$ hash -t cat
bash: hash: cat: not found
bash-5.1$ cat /etc/issue
Ubuntu 22.04.4 LTS \n \l
bash-5.1$ hash -t cat
/usr/bin/cat
bash-5.1$ PATH=/tmp:$PATH
bash-5.1$ hash -t cat
bash: hash: cat: not found
bash-5.1$ type cat
cat is /tmp/cat
bash-5.1$ cat /etc/issue
haha
bash-5.1$ rm /tmp/cat
bash-5.1$ type cat
cat is hashed (/tmp/cat)
bash-5.1$ hash -t cat
/tmp/cat
bash-5.1$ cat /etc/issue
bash: /tmp/cat: No such file or directory
bash-5.1$ hash -r
bash-5.1$ cat /etc/issue
Ubuntu 22.04.4 LTS \n \l
@b0rk Hey, Phind found the code for me in bash that clears the cache.
/* What to do just after the PATH variable has changed. */
void
sv_path (name)
char *name;
{
/* hash -r */
phash_flush ();
}
So yeah, no need to run hash after changing PATH. But hash -r is still useful in other cases.
@lemay @b0rk @nelson The case where you used to need to do this is if you first run a command from the shell, then you change the PATH so that the same command is found in a different place, but it still exists in the original place. bash consults the hash table first. If it says that foo is found in /usr/bin/foo, then you change PATH to put /home/b0rk/bin first, and there's a foo in that directory, bash would still run /usr/bin/foo unless you reset the hash.
But I just tried this and it now appears that the hash table is cleared if PATH is changed. So I think hash -r is no longer needed.
@lemay @b0rk @nelson I take that back. There's a way to produce the issue, just confirmed.
If the PATH is not changed, you've run a command where bash found your program in, say, the 3rd directory, then you add a command of the same name in an earlier directory, bash will run the wrong command unless you do hash -r .
@lemay @b0rk @nelson Here's a reproducer, assuming ls originally finds /usr/bin/ls :
export PATH=/home/me/dummy:$PATH
ls /usr/bin/ls
touch /home/me/dummy/ls
chmod +x /home/me/dummy/ls
ls /usr/bin/ls
You need hash -r to get bash to run your new ls, because the first ls command put ls -> /usr/bin/ls in the hash table.