Unix & Linux
linux bash path which
Updated Tue, 31 May 2022 09:43:25 GMT

Linux/bash does not execute the executable that "which" tells me


Observation: I have an executable named foo, located in /b/foo. It is compiled against an old header of a dynamic library, causing it to segfault when executed:

$ foo
Segmentation fault. // Expected behaviour.

Now, I compile a new version of foo to /a/foo against the new dynamic library that should execute just fine. Directory a/ is in my $PATH before b/, so /a/foo should be selected:

$ which foo
/a/foo

When I execute foo, the following happens:

$ foo
Segmentation fault.

Therefore, it seems that /b/foo gets executed, whereas "which" tells me that /a/foo should be executed. To make things weirder, when I run the full path $(which /a/foo), things run fine:

$ /a/foo
OK!
$ cp /a/foo .
$ ./foo
OK!

To go yet one step further, if I now delete /a/foo:

$ rm /a/foo

Then /b/foo must surely be chosen, right?

$ which foo
/b/foo
$ foo
bash: /a/foo: No such file or directory
$ $(which foo)
Segmentation fault. // Expected result.

Nope!

Fix: Source .bash_profile and .bashrc and the problem disappears.

Reproducibility: Every time. Just remove /a/foo, source ~/.bash_profile, create /a/foo, and the above observation re-occurs.

Question: Does anyone have an idea what went wrong here?

Hypothesis: "which" is up-to-date, but the system chooses based on "what was used to be the case". In my example above, /a/foo did not yet exist when the terminal was opened: I had only just created it. Therefore, when /a/foo was created, "which" did detect /a/foo, but the system still chose /b/foo, because it was somehow out of sync? But why is the system out of sync?




Solution

Bash caches the location of commands. Use hash foo to force it to update the cache.

Also, which is a separate command that doesn't tell you where your shell is actually looking; it just consults the $PATH environment variable. In bash, you should use type instead:

$ type foo
foo is hashed (/a/foo)




Comments (2)

  • +0 – Thank you for your answer. Just to add to your answer: After curiously trying some more, I found that a new executable is automatically added to the cache [hence I never noticed this before], whereas if an existing executable is changed/deleted, the cache will not know. — Jun 12, 2017 at 15:34  
  • +0 – That's just how all caches work: the first time some function is asked for a result, it does some work to determine that result, and then it remembers that answer so it doesn't have to redo the work. In this case, when you type a command, bash first looks in the cache. If it's not there, it searches the $PATH. If it finds it, it stores the result in the cache for next time. — Jun 12, 2017 at 15:38