240

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?

  • 4
    stupidiest feature ever – Romeno Jun 29 '18 at 15:57
305

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.

  • 15
    @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. – lunchmeat317 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 0:21
  • The above rehash command also works for zsh. – Neil Traft Nov 10 '13 at 21:35
  • For a more complete answer see unix.stackexchange.com/questions/86012/… – Ioannis Filippidis Aug 9 '14 at 0:43
  • 4
    In one command selective rehashing can be invoked by hash svnsync. – Ioannis Filippidis Aug 9 '14 at 0:44
24

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)

18

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
    
  • 1
    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
  • 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 7 '17 at 21:31
  • 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
4

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.

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.