linux commands

Linux which Command: Find Where a Command Is Installed

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:

QuestionCommand
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 pathtype -a NAME
Find an executable file through PATHwhich NAME
Find binaries, source, and manual-page locationswhereis 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:

  1. An alias
  2. A shell keyword
  3. A shell function
  4. A shell built-in
  5. 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.

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 ssh asks your shell what it will execute.
  • whereis ssh asks 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.

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.