14

Note that this is not a duplicate. I am asking about disabling the cache, not clearing it. If you have a cache to clear, then it is obviously not disabled.

On the rare occasions that I notice bash's cache of things that it has found in the path, it's not because it's helpful, it's because it's bloody annoying. An example:

~ dc$ export PATH=$HOME/bin:$PATH
~ dc$ cat bin/which
#!/bin/bash
echo "my which"
~ dc$ which
my which
~ dc$ rm bin/which
~ dc$ which which
-bash: /Users/dc/bin/which: No such file or directory

In another shell ...

~ dc$ which which
/usr/bin/which

I'm sure that this caching made sense back in the good old days when disks were slow and memory was expensive and limited and so you couldn't cache much - caching a path is cheaper than caching all the disk blocks necessary to find a command. But these days it provides no noticeable benefit and causes more problems than it solves. It's a misfeature, verging on being a bug.

And I can't even find a way of disabling it. Any pointers?

DrHyde
  • 522
  • 1
    The benefits are noticeable even in the common case of a desktop machine, if you don't have so much RAM that /usr/bin remains entirely in cache. – Gilles 'SO- stop being evil' Aug 19 '14 at 22:12
  • 2
    @drhyde, sorry. I marked this question as duplicate. Use set +h to disable hashing. – Evgeny Jul 28 '15 at 22:10
  • In Nixos, it disabled hash in its bash. I think, for a good reason because of Nixos way of working. However, I am not sure if this really mandatory for Nixos. I am only saying, that a hash in bash can bring problems in certain situations. – daparic May 24 '18 at 13:32

2 Answers2

14

You can just clear the hashed executables before the prompt gets drawn:

PROMPT_COMMAND='hash -r'

From help hash:

hash: hash [-lr] [-p pathname] [-dt] [name ...]
Remember or display program locations.

Determine and remember the full pathname of each command NAME.  If
no arguments are given, information about remembered commands is displayed.

Options:
  -d                forget the remembered location of each NAME
  -l                display in a format that may be reused as input
  -p pathname       use PATHNAME is the full pathname of NAME
  -r                forget all remembered locations
  -t                print the remembered location of each NAME, preceding
            each location with the corresponding NAME if multiple
            NAMEs are given
Arguments:
  NAME              Each NAME is searched for in $PATH and added to the list
            of remembered commands.

Exit Status:
Returns success unless NAME is not found or an invalid option is given.
Chris Down
  • 125,559
  • 25
  • 270
  • 266
9

You can force bash to do a new path lookup in case a command in the hash table does not exist anymore.

shopt -s checkhash

From bash's manpage:

checkhash

    If set, bash checks that a command found in the hash table exists before trying to execute it. If a hashed command no longer exists, a normal path search is performed.

Example:

[blabla]$ PATH=$HOME/bin:$PATH
[blabla]$ hash -r
[blabla]$ cat bin/which
#!/bin/bash
echo "my which"
[blabla]$
[blabla]$ shopt -s checkhash
[blabla]$ which
my which
[blabla]$ mv bin/which bin/dis.which
[blabla]$ which which
/usr/bin/which
user70408
  • 136