Linux which Command: Find Where a Command Is Installed
To find where a Linux command is installed, use command -v followed by the command name:
command -v python3
A typical result is:
/usr/bin/python3
You will also see people use which python3. That often works, but command -v is the better default in shell scripts and troubleshooting because it can identify aliases, functions, and shell built-insânot only executable files found through PATH.
This matters when a script says âcommand not found,â two servers run different versions, or your terminal launches a tool that is definitely not the one you thought you installed. Linux is usually doing exactly what its search path tells it to do. The annoying part is finding out what that is.
Quick answer: which command should you use?
Use this decision table:
| Question | Command |
|---|---|
| What will my current shell run? | command -v NAME |
| Is this an alias, function, built-in, or file? | type NAME |
| Show every matching command in my path | type -a NAME |
Find an executable file through PATH | which NAME |
| Find binaries, source, and manual-page locations | whereis NAME |
For everyday helpdesk work, start with:
command -v ssh
If the result looks surprising, follow with:
type -a ssh
That two-command workflow answers most âwhich copy am I actually running?â questions.
How Linux finds a command
When you enter a simple command such as:
curl https://example.com
Your shell must decide what curl means. Depending on the shell and command, it may check for:
- An alias
- A shell keyword
- A shell function
- A shell built-in
- An executable file in a directory listed in
PATH
PATH is an environment variable containing a colon-separated list of directories:
printf '%s\n' "$PATH"
Example:
/home/sam/.local/bin:/usr/local/bin:/usr/bin:/bin
The order matters. If both /usr/local/bin/report-tool and /usr/bin/report-tool exist, the shell normally uses the first matching executable it finds.
That explains a common support ticket: an admin installs a new version under /usr/local/bin, but a scheduled job still uses /usr/bin. The interactive shell and the job may have different PATH values, so both people can be right while the ticket remains irritating.
Use command -v as the reliable default
command -v reports how the current shell resolves a command:
command -v bash
command -v git
command -v python3
Possible output:
/usr/bin/bash
/usr/bin/git
/usr/bin/python3
It can also report shell features:
command -v cd
In Bash, the result may simply be:
cd
That is because cd is a shell built-in. There is no normal /usr/bin/cd program that could change the working directory of your existing shell.
Check whether a dependency exists
command -v is useful in scripts because it returns a success or failure status:
if command -v rsync >/dev/null 2>&1; then
echo "rsync is available"
else
echo "rsync is not installed or not in PATH"
fi
The redirection keeps the location out of normal output when you only need the yes-or-no answer.
Do not write this check using which in a portable shell script unless you control the environment. which is usually an external program, and its behavior varies between systems. command is built into POSIX-style shells.
Use type to reveal aliases and functions
The type command explains what kind of command your shell found:
type ls
You might see:
ls is aliased to `ls --color=auto'
Or:
ls is /usr/bin/ls
This is especially useful when a command behaves differently for one user. Their shell configuration may define an alias or function that changes the result.
Check all definitions with:
type -a python
Example:
python is /home/sam/.local/bin/python
python is /usr/bin/python
Now you know why typing python starts the user-local copy. The first match wins.
For a suspicious command, capture these in the ticket:
type -a tool-name
printf '%s\n' "$PATH"
tool-name --version
That is much better evidence than âit runs weird on Bobâs laptop.â
Use which for a quick executable lookup
The which command searches the current PATH for an executable:
which ssh
Typical output:
/usr/bin/ssh
Some implementations support -a to show every match:
which -a python3
This is convenient for interactive checks, and it is probably the command a coworker will suggest first. It is not useless. It is simply narrower and less consistent than command -v or type -a.
A beginner mistake is assuming which searches the entire filesystem. It does not. It normally searches only directories in PATH. A program can exist elsewhere and still produce no result.
Use whereis for related system locations
whereis searches common system locations for a commandâs binary, source, and manual page:
whereis ssh
Example:
ssh: /usr/bin/ssh /usr/share/man/man1/ssh.1.gz
This can help when you want both the program and its documentation. It is not the best answer to âwhat will my shell run?â because it does not follow shell aliases or functions and may show files outside the active PATH.
Think of the difference this way:
command -v sshasks your shell what it will execute.whereis sshasks the system where related SSH files exist in expected locations.
Those are different questions.
Troubleshoot âcommand not foundâ
Suppose a user runs:
backup-report
And gets:
bash: backup-report: command not found
Work through the problem in order.
1. Check whether the shell can resolve it
command -v backup-report
No output and a nonzero exit status means the current shell cannot resolve that name.
2. Inspect PATH one directory per line
printf '%s\n' "$PATH" | tr ':' '\n'
Look for the directory where the tool should have been installed, such as /usr/local/bin or $HOME/.local/bin.
3. Check the expected file directly
ls -l /usr/local/bin/backup-report
If the file exists, verify that it is executable:
test -x /usr/local/bin/backup-report && echo executable
If it is not executable, inspect ownership and permissions before changing anything. Do not jump directly to chmod 777; that creates a second problem and leaves the first one poorly understood.
4. Try the absolute path
/usr/local/bin/backup-report --version
If the absolute path works, the program exists and the likely problem is PATH, shell startup configuration, or the environment used by a service or scheduled job.
5. Refresh the shellâs command cache
Bash remembers command locations for speed. If you recently moved or replaced an executable, clear that cache:
hash -r
Then check again:
command -v backup-report
This is a small fix that can save a surprising amount of staring at a file that obviously exists.
Find out why the wrong version runs
Imagine you install a new utility and see:
toolbox --version
toolbox 1.8
But you expected version 2.4. Check every visible definition:
type -a toolbox
Example:
toolbox is /usr/bin/toolbox
toolbox is /opt/toolbox/bin/toolbox
Then compare:
/usr/bin/toolbox --version
/opt/toolbox/bin/toolbox --version
If /usr/bin appears before /opt/toolbox/bin in PATH, version 1.8 wins. You can fix the package, adjust PATH in the correct profile file, or call the required absolute path from automation.
Do not solve this by deleting the older binary until you know what installed it and what depends on it. Package managers dislike surprise renovations.
Interactive shell vs cron and systemd
A command can work in your terminal and fail in automation because the environments differ.
Your interactive shell may load .bashrc, .profile, or another startup file that adds:
/home/sam/.local/bin
A cron job often starts with a much smaller PATH. A systemd service uses the environment defined by its unit and manager configuration.
For a scheduled script, prefer explicit paths for critical tools:
/usr/bin/curl -fsS https://example.com/health
Or set a known path near the top of the script:
PATH=/usr/local/bin:/usr/bin:/bin
export PATH
To debug a cron environment, temporarily record it to a controlled log file, or add a diagnostic such as:
command -v python3 >> /var/tmp/job-debug.log 2>&1
Remove temporary diagnostics after the ticket is resolved. Leaving debug logs scattered around /var/tmp is how next monthâs disk-space ticket gets its origin story.
Check whether a result is a symlink
A command path may be a symbolic link:
command -v editor
ls -l "$(command -v editor)"
To resolve the final target on GNU/Linux:
readlink -f "$(command -v editor)"
This is useful for alternatives systems, version managers, and vendor tools that keep one stable command name pointing at a versioned binary.
Before replacing a symlink, document its current target. If the system uses update-alternatives, use that management tool rather than manually overwriting links it owns.
Common beginner mistakes
Assuming which searches every disk
which searches PATH. Use a known package manager, find, or system inventory tools when the executable is not in the active path.
Ignoring aliases
An alias can override the executable you expected. Use type NAME, not only which NAME.
Running sudo too early
You do not need sudo to inspect PATH, run command -v, or use type. Running every diagnostic through sudo can change the environment and hide the user-specific problem.
Compare carefully when needed:
command -v python3
sudo sh -c 'command -v python3'
A difference is a clue, not an invitation to copy rootâs environment everywhere.
Editing PATH in the wrong file
Bash login shells, interactive shells, Zsh, cron, and systemd do not necessarily read the same files. Identify the affected context before editing .bashrc, .profile, /etc/environment, a crontab, or a systemd unit.
Trusting the path without checking the version
Finding /usr/bin/python3 answers where it is. It does not answer which version it is:
python3 --version
Record both location and version when a ticket involves inconsistent behavior.
A practical helpdesk checklist
When a command is missing or wrong, collect:
whoami
hostname
printf '%s\n' "$SHELL"
printf '%s\n' "$PATH"
command -v tool-name
type -a tool-name
tool-name --version
If the tool resolves to a file, add:
ls -l "$(command -v tool-name)"
This tells the next technician which account, machine, shell, path, command location, definition, version, owner, and permissions were involved. That is a ticket note someone can actually use.
Practice the workflow safely
The commands in this guide are simple, but the surrounding ideasâPATH order, aliases, executable permissions, absolute paths, and different automation environmentsâshow up constantly in Linux work.
Practice Linux command-line troubleshooting in Shell Samurai. It gives you a safe place to build the habit of checking what the shell sees before changing a live system and discovering that the âmissingâ command was sitting behind the wrong path the whole time.
FAQ
What is the Linux equivalent of where.exe on Windows?
command -v NAME is the best general answer for what your current shell will run. which NAME is the familiar executable-path lookup. Use type -a NAME to see aliases, functions, built-ins, and all matching executable locations.
Why does which return nothing when the file exists?
The file may be outside PATH, lack executable permission, or have a different name. which does not search the entire filesystem.
Why do command -v and which show different results?
The name may be an alias, function, or shell built-in. command -v understands the current shellâs command resolution, while which usually searches executable files in PATH.
How do I show all installed versions of a command?
Start with type -a NAME and, where supported, which -a NAME. These show matches visible through the shell and PATH; they do not guarantee that every copy anywhere on disk will appear.
How do I get the full path of a Linux command?
Run command -v NAME. If it returns an executable path, you can resolve symlinks with readlink -f "$(command -v NAME)" on GNU/Linux.
Practice This in a Real Terminal
Shell Samurai gives you safe Linux missions so the commands actually stick. Chapter 1 is free; the full practice path is a one-time purchase, not another subscription.