The which command displays the full path to an executable that your shell would run when you type a command name. This helps you identify which program version runs, verify that a tool exists in your PATH, and ensure scripts reference the correct binary. By the end of this guide, you will understand how to locate executables, handle multiple matches, recognize shell built-in limitations, and choose the right lookup tool for different situations.
Understanding the which Command
When you type a command like ls or python3, your shell searches directories listed in the PATH environment variable until it finds a matching executable. The which command performs this same search and reports the path it would use. Understanding this behavior helps you troubleshoot path-related issues and verify installations.
You will find this command useful in several situations. System administrators often need to verify that a specific tool version remains accessible. Script writers use which to confirm that required commands exist before running. Developers working with multiple language versions rely on it to check which interpreter runs by default.
Implementation Differences
Linux distributions ship two main implementations of which, and these differences determine which options you can use.
GNU which (Fedora, RHEL, Arch, openSUSE, Gentoo)
- Supports extended options like
--skip-dot,--show-tilde, and alias handling - Prints explicit error messages when a command is not found
- Supports
--versionto check the implementation
Minimal which (Debian, Ubuntu, and derivatives)
- Supports only
-a(show all matches) and-s(silent mode) - Returns silently with exit code 1 when a command is not found
- Does not support
--versionor other GNU options
Basic Syntax
The fundamental structure is straightforward:
which command_name
For example, to find the location of ls:
which ls
On most Linux systems, this returns:
/usr/bin/ls
The output indicates that running ls executes the binary at /usr/bin/ls.
Available Options
The options available depend on your distribution’s implementation.
Universal option (all implementations)
-a: Print all matching executables in PATH, not just the first one
Minimal which only (Debian, Ubuntu, and derivatives)
-s: Silent mode; return exit code only without printing paths (useful for scripts)
GNU which only (Fedora, RHEL, Arch, openSUSE, Gentoo)
--version: Display version information--skip-dot: Skip directories in PATH that start with a dot--skip-tilde: Skip directories in PATH that start with a tilde--show-dot: Do not expand a dot to the current directory in output--show-tilde: Output a tilde for HOME directory (non-root users)-ior--read-alias: Read alias definitions from stdin
If you attempt to use GNU-specific options on Debian or Ubuntu, you will see an error like
Illegal option --because the minimal implementation does not recognize them.
Practical Examples
Locate Common Utilities
Finding the path to text-processing tools helps when building scripts that need absolute paths:
which grep
/usr/bin/grep
Similarly, you can locate archive and stream-editing utilities:
which tar awk
/usr/bin/tar /usr/bin/awk
When querying multiple commands, which prints each path on a separate line in the order you specified. For related text-processing tasks, consider our grep command guide or sed command tutorial.
Verify Software Installation
After installing software, you can confirm your PATH includes it:
which python3
When Python 3 exists and appears in your PATH, you will see:
/usr/bin/python3
When the command produces no output and returns to the prompt, the executable either does not exist or does not appear in your PATH. On Debian and Ubuntu systems, the absence of output indicates the command was not found. In contrast, GNU which on Fedora explicitly states this:
which: no python3 in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
Display All Matches with -a
The -a option reveals all matching executables across your entire PATH. This option proves essential when multiple versions of a program exist:
which -a ls
/usr/bin/ls /bin/ls
Both paths point to the same binary in this case because /bin typically links to /usr/bin on modern systems (called “merged /usr”). The first path listed is the one your shell would execute.
This option becomes more useful when you have installed multiple versions of software. For example, if you compiled Python locally alongside the system version:
which -a python3
/usr/local/bin/python3 /usr/bin/python3
The first path listed is the one your shell would execute. In this case, the locally compiled version in /usr/local/bin takes priority. Combining this with --version confirms which version runs by default:
$(which python3) --version
Python 3.x.x
Check Shell Location
System administrators often need to verify which shell is being used:
which bash
/usr/bin/bash
This path is commonly used in script shebang lines (#!/usr/bin/bash) to ensure the correct interpreter runs the script.
Understanding Exit Codes
The which command returns specific exit codes that scripts can use for conditional logic:
- Exit code 0: All specified commands were found
- Exit code 1: One or more commands were not found
- Exit code 2: Invalid option specified (GNU which only)
You can use these exit codes in scripts to check whether a command exists before attempting to use it:
if which docker > /dev/null 2>&1; then
echo "Docker is installed at $(which docker)"
else
echo "Docker is not installed"
fi
The redirection to /dev/null suppresses output, and the script uses only the exit code for the conditional check. For more shell scripting techniques, see our bash wait command guide.
Shell Built-ins vs External Commands
Some commands like cd, echo, and pwd exist both as shell built-ins and as external executables. However, the which command only searches for files in PATH directories, so it cannot detect built-ins.
which echo
/usr/bin/echo
This output shows the external /usr/bin/echo binary, but when you type echo in bash, the shell actually uses its built-in version for performance reasons. To see what your shell would actually execute, use the type command instead:
type echo
echo is a shell builtin
For commands that exist only as built-ins with no external equivalent, which returns nothing:
which cd
Running this produces no output because cd is purely a shell built-in. The type command correctly identifies it:
type cd
cd is a shell builtin
Alternatives to which
While which works well for finding executables, several other tools offer different capabilities or better portability across systems.
The command -v Approach
The POSIX-compliant command -v is available in all shells and does not require external packages:
command -v ls
/usr/bin/ls
Unlike which, this approach also works for shell functions and built-ins, making it more versatile. Many shell scripting guides recommend command -v over which because every POSIX-compliant system includes it, even minimal containers where which might not exist.
The type Command
The type shell built-in shows how your shell interprets a command, distinguishing between aliases, functions, built-ins, and external commands:
type ls
ls is /usr/bin/ls
If ls were aliased (common on many systems), type would show the alias definition instead. To see all definitions, use type -a:
type -a echo
echo is a shell builtin echo is /usr/bin/echo echo is /bin/echo
This output shows that bash uses its built-in echo by default, with two external binaries available as fallbacks. The order matters because the shell tries each one from top to bottom.
Comparison Table
| Tool | Finds Built-ins | Finds Aliases | POSIX Portable | Best Use Case |
|---|---|---|---|---|
which | No | No | No | Quick external binary lookup |
command -v | Yes | Yes | Yes | Portable scripts, minimal systems |
type | Yes | Yes | Yes | Understanding shell behavior |
Advanced Usage
Verify Developer Tools
Before compiling software, you should verify that your system has the necessary build tools:
which gcc make cmake
If all tools are installed, you will see their paths. Missing tools produce no output on Debian and Ubuntu, or explicit error messages on Fedora. Consequently, this quick check helps identify what needs to be installed before starting a build process.
Locate Custom Scripts
Custom scripts stored in ~/bin or ~/.local/bin become accessible when you include those directories in your PATH. Verify accessibility with:
which myscript
When the script appears in your PATH and has execute permission, you will see its full path. Otherwise, check that the directory appears in PATH and that the script has execute permission. You can set execute permission with chmod +x myscript. For a complete overview of permission management, see our chmod command guide.
Priority in PATH
When the same command exists in multiple PATH directories, the shell uses the first match. The which command shows you which version takes priority:
which python3
If you have installed Python locally to /usr/local/bin and that directory appears before /usr/bin in your PATH, the local version runs by default. Use which -a python3 to see all available versions and their order.
Troubleshooting
Command Not Found But Installed
If you installed software but which returns nothing, the executable likely does not exist in your PATH. First, check the installation location, then verify your PATH includes that directory:
echo $PATH
Common locations that might not appear in PATH by default include /usr/local/bin, /opt/program/bin, and ~/.local/bin. If needed, add the directory to your PATH in ~/.bashrc:
export PATH="$PATH:/path/to/new/directory"
After editing, reload your shell configuration with source ~/.bashrc or open a new terminal.
Illegal Option Error
If you see Illegal option -- when using options like --version, you are using the minimal which implementation (Debian, Ubuntu, and derivatives), which only supports -a and -s. For extended functionality, use type or command -v instead, as these are built into your shell.
Hash Table Caching
Bash caches command locations for performance. If you install a new version of a command, your shell might still use the cached path. To view the current cache, run:
hash
hits command 3 /usr/bin/which 1 /usr/bin/grep
Clear the cache with:
hash -r
After running this command, both which and the command itself will search PATH fresh. You can verify the cache is empty by running hash again:
hash
hash: hash table empty
Conclusion
The which command provides a quick way to locate executables in your PATH, verify installations, and identify which version of a program runs by default. For scripts needing maximum portability, consider using command -v instead. Similarly, use type when you need to understand how your shell interprets a command, including aliases and built-ins. Together, these tools give you complete visibility into where your commands come from and which versions your shell will execute.