The Unix
which command is useful for searching your
$PATH to find which version of an executable is going to run. But did you know that it doesn't always tell you the truth? For instance, it doesn't tell you when the command you're asking about is hidden by a shell builtin (or function, keyword, or alias):
$ which echo
/usr/bin/echo
which found /usr/bin/echo on your path, but
echo is a shell builtin (at least in bash), so that's what will get run, not the one on the path. The GNU man page for
which presents workarounds that will pick up functions and aliases, but shell builtins still slip through the cracks. The situation is even weirder on Solaris, where
which is a
csh shell-script, that sources your
.cshrc file as part of its operation -- very strange if your shell is bash.
Clearly,
which is not to be trusted. The easiest workaround, if you use bash, is the
type builtin:
$ type -a echo
echo is a shell builtin
echo is /bin/echo
A slightly nicer workaround is to make a
bash function for
which, that uses
type to do the right thing. I also like
which to do an
ls -l where applicable. Here's what I have in my .bashrc:
if alias which > /dev/null 2>&1; then unalias which; fi
function which {
hash -r
t=`type -t $@`
if [ -z "${t%%file*}" ]; then
for p in `type -p $@`; do
ls -l ${p};
done
else
type $@;
fi
}
Now
which gives you much more information:
$ which -a wish
lrwxrwxrwx 1 root root 13 Dec 23 2008 /usr/local/bin/wish -> /usr/bin/wish*
lrwxrwxrwx 1 root root 7 Jan 8 2007 /usr/bin/wish -> wish8.3*
The unalias protects you in case some systemwide .bashrc or .profile aliases which in some way (unlikely, but good hygiene anyway). The call to
hash clears the hashed function list, so that any changes to your PATH are reflected. The reason for the
if statement in the function, is that we certainly want to report builtins, functions, etc., but if there are none, we can use
type -p to make it easier to pass the filenames to
ls -l. If there are builtins or such, we just punt and give the unaltered
type output.
You can pass
-a to this
which if you want to see all the matches for the command, in order of precedence.
Note that this has to be a function, not a script, because running the script will source your .bashrc, which might change the PATH (all PATH changes should be in .profile, but sometimes people do it in .bashrc).