opscape

Finding things

which

Show which executable file in PATH would run for a command name.

which [-as] COMMAND...

7 of 7 examples run in Debian 13.7 on 2026-10-31 · manual: which(1)

which searches the directories in $PATH, in order, and prints the full path of the first executable file with the given name: the program that would run if you typed that name. It is the quick answer to "which python is this?" or "why does my script get the old version?".

It is an external program and only knows about files. It cannot see shell builtins (cd, echo), functions or aliases, which the shell checks before searching PATH, so for those it prints nothing or the wrong answer. In bash, type -a name shows everything the shell would consider, and in scripts the portable test for "is this command available?" is command -v name.

On Debian and Ubuntu which is a small shell script from debianutils with two options, -a and -s. Other systems have other implementations (GNU which, the BSD one, a zsh builtin) with different options and output, another reason to prefer command -v in scripts.

Examples

Find the program a command runs

which grep
explain
output
/usr/bin/grep

The first match in $PATH is printed. Exit status 0 means it was found.

Look up several names at once

which python3 nosuchcmd jq
explain
outputexit 1
/usr/bin/python3
/usr/bin/jq

Each name found is printed; missing names print nothing. The exit status is 1 because at least one name was not found.

Show every match in PATH with -a

which -a ls
explain
output
/usr/bin/ls
/bin/ls

-a lists all executables with that name, in PATH order; the first is the one that runs. On Debian with merged /usr, /bin is a symlink to /usr/bin, so the same file appears under both directories.

Spot a command shadowed earlier in PATH

Setup run before this example
mkdir -p /home/dev/bin
printf '#!/bin/sh\necho "my own ls"\n' > /home/dev/bin/ls
chmod +x /home/dev/bin/ls
PATH="$HOME/bin:$PATH"
which -a ls
ls
output
/home/dev/bin/ls
/usr/bin/ls
/bin/ls
my own ls

A directory earlier in PATH wins. which -a makes the problem visible: ~/bin/ls comes first, so typing ls runs it instead of the real one.

which cannot see builtins, aliases or functions

greet() { echo hi; }
which cd greet echo; echo "which exit status: $?"
type cd greet echo
output
/usr/bin/echo
which exit status: 1
cd is a shell builtin
greet is a function
greet () 
{ 
    echo hi
}
echo is a shell builtin

which finds nothing for cd or the function, and for echo it reports /usr/bin/echo although bash would run its builtin. type asks the shell itself and gets all three right, printing the function's body. Aliases are invisible to which in the same way.

Follow alternatives and symlinks to the real file

which awk
readlink -f "$(which awk)"
output
/usr/bin/awk
/usr/bin/gawk

/usr/bin/awk is a symlink managed by Debian's alternatives system. readlink -f resolves the chain and shows that awk is gawk here.

Test whether a command exists

if which -s jq; then echo "jq is installed"; fi
if command -v rg >/dev/null; then echo "rg found"; else echo "rg not installed"; fi
output
jq is installed
rg not installed

-s prints nothing and only sets the exit status. It works with Debian's and the BSD which, but not every version; command -v is the POSIX form and is what scripts should use.

Common pitfalls

  • which ignores aliases, functions and builtins, so its answer can differ from what actually runs. Use type -a in bash.

  • Do not use which in portable scripts to check for a program: implementations differ in options, output and even exit status. command -v name >/dev/null is POSIX.

  • bash remembers where it found a command (hash). After installing a new version earlier in PATH, the shell may still run the old one even though which shows the new path. Run hash -r.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • Debian and Ubuntu use the debianutils which (-a, -s). Red Hat-family systems use GNU which, which can also read aliases with --read-alias. macOS has a BSD which that supports -a and -s. zsh has which as a builtin that does report aliases and functions.

Options worth knowing

A selection, described in our own words. For the full list, see which(1) or which --help.

OptionWhat it does
-aPrint every matching executable in PATH, not just the first.
-sPrint nothing; only set the exit status.

Related