which

Find a command on PATH, and nowhere else

Updated 2026-09-05

which searches PATH for an executable file and prints the first one it finds. That is the whole of it, and everything below follows from it: the order of the directories in PATH decides the answer, and anything that is not a file on PATH has no answer at all. It will tell you there is no cd. which vs type vs command -v is that limit in full, and what to use instead.

On Debian this is not the GNU program people expect. It is a small /bin/sh script from debianutils, reached through the alternatives system, and it takes -a and -s and nothing else, so a --version you inherited from another system is an error here. It was deprecated in 2021, and the deprecation was reversed by a Technical Committee ruling a few months later, which is why it is still on every Debian machine.

12 outputs, collapsed by default

What it searches

which walks the directories in PATH from left to right and prints the first executable file matching each name. It knows nothing about aliases, functions or builtins, which is a comparison of its own.

Ask about several commands at once

which ls cat nosuchthing; echo "exit $?"

Each argument is looked up in turn and the misses are simply absent from the output. The status is 1 because one of them failed, so a script cannot read it as "none were found".

Show output
/usr/bin/ls
/usr/bin/cat
exit 1

See every match instead of the first

which -a sh

-a keeps going after the first hit. Two answers here for one program: Debian's usrmerge makes /bin a symlink to /usr/bin, so the same file is reachable by two paths and both are on PATH.

Show output
/usr/bin/sh
/bin/sh

Ask without wanting the answer printed

which -s ls; echo "found: $?"; which -s nosuchcommand; echo "missing: $?"

-s reports through the exit status alone. It is one of the two options this which has, and it is not in every implementation, so a portable script wants command -v instead.

Show output
found: 0
missing: 1

Find the manual page as well as the binary

whereis ls

whereis looks in a fixed set of standard directories rather than at PATH, and reports the binary, the source and the manual page. A different question from the one which answers, and it comes from the util-linux package.

Show output
ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz

When PATH order decides the answer

The first match wins, so the order of the directories in PATH is the whole resolution rule. It is also how a command gets replaced without anybody noticing.

Shadow a command from a directory earlier on PATH

mkdir -p tools && printf "#!/bin/sh\necho fake\n" > tools/ls && chmod +x tools/ls && PATH="tools:$PATH" which ls

tools comes first, so tools/ls is the answer and the real ls is never reached. Prepending to PATH is how a project's own scripts take precedence, and how a stray executable quietly replaces a system command.

Show output
tools/ls

See what was shadowed

mkdir -p tools && printf "#!/bin/sh\necho fake\n" > tools/ls && chmod +x tools/ls && PATH="tools:$PATH" which -a ls

-a shows the whole search in order, which is the quickest way to answer "why am I getting a different ls than I expected". Environment variables and PATH covers how PATH gets set.

Show output
tools/ls
/usr/bin/ls
/bin/ls

See what the shell has already looked up

ls -d . >/dev/null; hash

The shell remembers where it found a command so it need not search PATH again, and which knows nothing about that table. hash -r empties it, which is the fix on the rare occasion a command has moved under a running shell.

Show output
hits	command
   1	/usr/bin/ls

The which Debian actually ships

It is not the GNU program, and knowing that saves a puzzled minute the first time a flag you expected is refused.

Read the first two lines of it

head -2 /usr/bin/which

A shell script, not a compiled program. It is short enough to read in full, and reading it is the fastest way to be sure what it does and does not do.

Show output
#! /bin/sh
set -ef

Follow it to the real file

readlink /usr/bin/which; readlink -f "$(command -v which)"

/usr/bin/which is managed by the alternatives system, so the name on PATH points into /etc/alternatives and only then at the implementation.

Show output
/etc/alternatives/which
/usr/bin/which.debianutils

Find which package it came from

dpkg -S "$(readlink -f "$(command -v which)")"

debianutils, which is priority required, so it is on every Debian system. dpkg -S answers this for any file that a package placed.

Show output
debianutils: /usr/bin/which.debianutils

Ask it for a version

which --version 2>&1; echo "exit $?"

There is no --version, and no --help either. The options are -a and -s, and anything else is an error with exit status 2. A script written against GNU which fails here.

Show output
Illegal option --
Usage: /usr/bin/which [-as] args
exit 2

Read why it is still here

zcat /usr/share/doc/debianutils/changelog.gz | grep -iE "deprecate which|revert deprecation of which"

The changelog is newest first, so the reversal is printed above the deprecation it undid. which was deprecated in 2021 and restored by a Technical Committee ruling, and the package has shipped it ever since.

Show output
  * Revert deprecation of which (no. 2).
  * Deprecate which.