11

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?

  • 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
  • 1
    @drhyde, sorry. I marked this question as duplicate. Use set +h to disable hashing. – Evgeny Vereshchagin 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. – typelogic May 24 '18 at 13:32
12

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.
  • 1
    see my answer about set +h – Evgeny Vereshchagin Jul 27 '15 at 18:27
  • 1
    @EvgenyVereshchagin set +h isn't ideal, as many utilities (e.g. ruby gem installations) call hash, producing streams of -bash: hash: hashing disabled warnings. – David Moles Feb 20 '18 at 18:56
  • I also see the same warning messages in a python virtualenv activation. But I think, it is harmless. – typelogic May 24 '18 at 13:34
7

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.