367

When I execute a program without specifying the full path to the executable, and Bash must search the directories in $PATH to find the binary, it seems that Bash remembers the path in some sort of cache. For example, I installed a build of Subversion from source to /usr/local, then typed svnsync help at the Bash prompt. Bash located the binary /usr/local/bin/svnsync for "svnsync" and executed it. Then when I deleted the installation of Subversion in /usr/local and re-ran svnsync help, Bash responds:

bash: /usr/local/bin/svnsync: No such file or directory

But, when I start a new instance of Bash, it finds and executes /usr/bin/svnsync.

How do I clear the cache of paths to executables?

  • 40
    stupidiest feature ever – Unicorn Jun 29 '18 at 15:57
  • 3
    The bash cache car crash? – gm3dmo Apr 03 '20 at 07:48
  • 6
    @Romeno The feature is nice (it save time when you re-run a command), it's the implementation that's stupid. Bash should be automatically dropping hashes for which the executable is not there anymore. – Dmitry Grigoryev Aug 31 '20 at 23:50
  • @DmitryGrigoryev Another scenario is that I install a new version of an executable, or change the value of PATH, specifically to use that new version rather than some old version that I tried and didn't work. – Imperishable Night Feb 17 '21 at 00:51

4 Answers4

463

bash does cache the full path to a command. You can verify that the command you are trying to execute is hashed with the type command:

$ type svnsync
svnsync is hashed (/usr/local/bin/svnsync)

To clear the entire cache:

$ hash -r

Or just one entry:

$ hash -d svnsync

For additional information, consult help hash and man bash.

Mattie
  • 105
Tobu
  • 6,593
  • 22
    @Daniel It's worth adding that, in bash, you can use the command "type command" to find out what type of command it is - if your command is hashed, "type" will tell you. It's also useful to tell whether something's a shell builtin or an alias. –  May 11 '11 at 20:59
  • 4
    As an FYI, to change the cached PATH if running csh, the command is rehash. – kurtm Oct 12 '13 at 00:21
  • The above rehash command also works for zsh. – Neil Traft Nov 10 '13 at 21:35
  • For a more complete answer see http://unix.stackexchange.com/questions/86012/what-is-the-purpose-of-the-hash-command – 0 _ Aug 09 '14 at 00:43
  • 4
    In one command selective rehashing can be invoked by hash svnsync. – 0 _ Aug 09 '14 at 00:44
  • for me solved the issue bash: /usr/local/bin/vagrant: No such file or directory – gorodezkiy Aug 27 '15 at 06:18
  • 1
    I discovered I was running dash instead of bash - for dash hash -d doesn't work; hash svnsync works for both however. – Iiridayn Jul 19 '16 at 00:10
  • What does the r in -r stand for? I always forget this option. "reset" maybe? – flow2k Mar 09 '20 at 18:26
  • 2
    I'm curious, any idea on how to do this from inside a script in a way that affects the parent shell? None of the methods in the answers work for this use case. – AlexanderF Oct 22 '20 at 20:03
  • @flow2k It probably means reset or remove (all). Since it's a bash built-in the man page isn't so helpful but neither is help. It doesn't say anything but: forget all remembered locations. You could just guess that it means reset and be done with it. – Pryftan Oct 26 '22 at 18:08
  • You have 2 commands for discovering what is the origin of a command: type and which. which will give you the location in the $PATH. type will let you know the executable is hashed. If this is the case, you can run hash -r to resync the commands. – jlguenego Apr 02 '23 at 09:37
37

There are solutions not mentioned here.

  1. You can disable hashing with set +h or set +o hashall

    help set says:

    -h - Remember the location of commands as they are looked up for execution. This is enabled by default.

    hashall - Same as -h

    set -h # enable hashing
    shopt -u checkhash # disable command existence check
    hash -p /some/nonexisting/dir/date date # bind date with /some/nonexisting/dir/date
    date # bash: /some/nonexisting/dir/date: No such file or directory
    set +h
    date # normal date output
    
  2. You can check that a command found in the hash table exists before trying to execute it with shopt -s checkhash

    help shopt says:

    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.

    set -h # enable hashing
    shopt -u checkhash # disable command existence check
    hash -p /some/nonexisting/dir/date date # bind date with /some/nonexisting/dir/date
    hash -t date # prints /some/nonexisting/dir/date
    date # bash: /some/nonexisting/dir/date: No such file or directory
    shopt -s checkhash # enable command existence check
    date # normal date output
    hash -t date # prints /bin/date
    
  3. You can bind NAME with PATH with hash -p PATH NAME or BASH_CMDS[NAME]=PATH:

    shopt -u checkhash # disable command existence check
    hash -p /some/nonexisting/dir/date date
    date # bash: /some/nonexisting/dir/date: No such file or directory
    BASH_CMDS[date]=/bin/date
    date # normal date output
    
  4. Magic: PATH="$PATH" performs hash -r

    From variables.c:

    /* What to do just after the PATH variable has changed. */
    void
    sv_path (name)
        char *name;
    {
        /* hash -r */
        phash_flush ();
    }
    

    Try:

    set -h
    hash -r
    date
    hash # prints 1 /bin/date
    PATH="$PATH"
    hash # prints hash: hash table empty
    
Evgeny
  • 5,476
  • 3
    I've never understood why all the extra mechanism is supplied when PATH=$PATH works just fine. If the PATH changes, then the PATH lookup cache should be invalidated. Makes sense. – jrw32982 Jul 27 '16 at 19:48
  • 1
    The use case not handled by invalidating the cache when the PATH changes is when the locations of executables change. This can be common when you are using the shell to add or remove programs, only to have it cache the last place it found them. – Adam Dec 07 '17 at 21:31
  • 1
    Messing with the command hash table is a wonderful way to really confuse someone who is trying to debug a bash script. – Erik Aronesty Jan 29 '18 at 18:12
29

To clear just one entry you need a different flag:

hash -d svnsync

The -r flag doesn't take a parameter and will always delete the entire cache.
(At least in bash 3.2.39 on Debian Lenny)

Kevin
  • 40,767
11

As user johntex has noted in a comment to the answer by user Tobu, the simplest practical action in Bash is to rehash just your program:

hash svnsync

That's all.

Asclepius
  • 426