Shell – the difference between which and where

linuxshell-builtinwhichzsh

What is the difference between where and which shell commands?
Here are some examples

 ~  where cc
/usr/bin/cc
/usr/bin/cc
~  which cc
/usr/bin/cc

and

  ~  which which
which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
/usr/bin/which
  ~  which where
/usr/bin/which: no where in (/usr/local/bin:/bin:/usr/bin:/home/bnikhil/bin:/bin)

also

  ~  where which
which: aliased to alias | /usr/bin/which --tty-only --read-alias --show-dot
 --show-tilde
which: shell built-in command
/usr/bin/which
/usr/bin/which
  ~  where where
where: shell built-in command

To me it seems that they do the same thing one being a shell builtin, not quite sure how that is different from a command?

Best Answer

zsh is one of the few shells (the other ones being tcsh (which originated as a csh script for csh users, which also had its limitation, tcsh made it a builtin as an improvement)) where which does something sensible since it's a shell builtin, but somehow you or your OS (via some rc file) broke it by replacing it with a call to the system which command which can't do anything sensible reliably since it doesn't have access to the interns of the shell so can't know how that shell interprets a command name.

In zsh, all of which, type, whence and where are builtin commands that are all used to find out about what commands are, but with different outputs. They're all there for historical reason, you can get all of their behaviours with different flags to the whence command.

You can get the details of what each does by running:

info -f zsh --index-search=which

Or type info zsh, then bring up the index with i, and enter the builtin name (completion is available).

And avoid using /usr/bin/which. There's no shell nowadays where that which is needed. As Timothy says, use the builtin that your shell provides for that. Most POSIX shells will have the type command, and you can use command -v to only get the path of a command (though both type and command -v are optional in POSIX (but not Unix, and not any longer in LSB), they are available in most if not all the Bourne-like shells you're likely to ever come across).

(BTW, it looks like /usr/bin appears twice in your $PATH, you could add a typeset -U path to your ~/.zshrc)

Related Question