4

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?

1 Answers1

9

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)
Mark Reed
  • 212
  • 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. – Kevin van As Jun 12 '17 at 15:34
  • 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.

    – Mark Reed Jun 12 '17 at 15:38