373

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
  • 41
    stupidiest feature ever
    – Unicorn
    Commented Jun 29, 2018 at 15:57
  • 3
    The bash cache car crash?
    – gm3dmo
    Commented Apr 3, 2020 at 7:48
  • 7
    @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. Commented Aug 31, 2020 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. Commented Feb 17, 2021 at 0:51

4 Answers 4

468

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.

11
  • 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.
    – user6517
    Commented May 11, 2011 at 20:59
  • 4
    As an FYI, to change the cached PATH if running csh, the command is rehash.
    – kurtm
    Commented Oct 12, 2013 at 0:21
  • 4
    In one command selective rehashing can be invoked by hash svnsync.
    – 0 _
    Commented Aug 9, 2014 at 0:44
  • 1
    I discovered I was running dash instead of bash - for dash hash -d doesn't work; hash svnsync works for both however.
    – Iiridayn
    Commented Jul 19, 2016 at 0:10
  • 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
    Commented Oct 22, 2020 at 20:03
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
    
3
  • 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
    Commented Jul 27, 2016 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
    Commented Dec 7, 2017 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. Commented Jan 29, 2018 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)

0
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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .