32.6 which, whereis, and type: Finding Executables
Before we dive into the big, complex tools, let’s start with the easy wins. You’re at the command line, you type a command like nmap, and bash hits you with a “command not found.” Or worse, it runs a version of the command, but it’s the wrong one. Your first instinct shouldn’t be to break out the heavy artillery like find; it should be to ask a simple question: “Where the heck is this thing?”
That’s what which, whereis, and type are for. They’re your first responders for locating executables. They each have a slightly different search strategy, and knowing which to use is half the battle.
The One-Trick Pony: which
which is the simplest of the bunch. Its entire job is to tell you the full path of the executable that will run when you type a command. It does this by searching through the directories listed in your PATH environment variable, in order, and spitting out the first match it finds.
$ which python
/usr/bin/python
$ which ls
/bin/ls
This is incredibly useful for debugging those “why is it running the wrong version?!” problems. Let’s say you installed a new, shiny version of Python in /usr/local/bin, but your old crusty system Python is still hanging around.
$ which python
/usr/bin/python # Oh no, the old one!
$ echo $PATH
/usr/local/bin:/usr/bin:/bin # Wait, /usr/local/bin is first! Why isn't it found?
Ah-ha! The which command revealed the issue. Your PATH is set correctly, so why is it finding the old one? The plot thickens. Maybe the new one isn’t actually named python? Time to look in that directory with ls /usr/local/bin/python*. See how which gave you the first clue?
The Big Limitation: which is a blunt instrument. It’s an external command that only looks for executables in your PATH. It knows nothing about shell builtins or aliases, which leads to hilarious and confusing lies.
$ which cd
/usr/bin/which: no cd in (/usr/local/bin:/usr/bin:/bin)
Wait, what? cd obviously exists! This brings us to our next, more knowledgeable command.
The Shell’s Insider: type
While which is an external program asking the system, type is a bash builtin asking the shell itself. The shell knows all its own secrets: aliases, builtins, functions, and keywords. It’s the ultimate authority on what your command line is actually going to do.
$ type cd
cd is a shell builtin
$ type ls
ls is aliased to 'ls --color=auto'
$ type which
which is /usr/bin/which
$ type function_name
function_name is a function
This is the truth. When which failed to find cd, type immediately knew it was a builtin command. When you’ve set a fancy alias for ls, type reveals it. You should basically never use which when you can use type. It’s strictly more accurate for understanding your shell’s behavior. Consider which deprecated for interactive use.
The Thorough Investigator: whereis
If which is a one-trick pony and type is a savvy insider, whereis is the librarian who brings you the whole box of related files, not just the one you asked for. It doesn’t just search your PATH; it hunts through a list of standard directories (/bin, /sbin, /usr/bin, /usr/share/man, etc.) for the program’s binary, its source code, and its manual pages.
$ whereis ls
ls: /bin/ls /usr/share/man/man1/ls.1.gz
$ whereis python
python: /usr/bin/python /usr/bin/python2.7 /usr/lib/python2.7 /etc/python2.7 /usr/share/man/man1/python.1.gz
This is great for getting a more complete picture of where a package installed all its components. The man page location is particularly handy. The trade-off is that it’s less precise. It might show you /usr/bin/python even if /usr/local/bin/python is the one first in your PATH, because it’s not consulting PATH the same way. It’s showing you all instances it can find in its predefined haunts.
Best Practices and Pitfalls
- Default to
type. For figuring out why a command behaves the way it does,typeis your best friend. It’s the only one that tells you about aliases and builtins. - Use
whichfor scripting (carefully). Sincetypeis a shell builtin, it behaves differently in scripts versus interactive shells.whichis a standard external command whose behavior is more consistent across environments. But always be aware of its limitations. - Use
whereisfor a broader context. When you need more than just the executable path—like the man page or you’re trying to find all versions of something on the system—whereisis your tool. - Remember, they all have blind spots. None of these tools will find a script or binary that’s not in the standard directories or your
PATH. If you downloaded a singlecool_toolbinary and put it in~/Projects/, these commands won’t see it. For that, you need to graduate to the real search tools.