Home / Alt manpages / which.debianutils(1)

  • which.debianutils(1)
  • User command
  • linux

Find the Executable Your Shell Will Use with which

You will use Debian's which to see which executable a command name resolves to, inspect every matching file on PATH, and check lookup results in scripts without printing them. The examples use Debianutils package version 5.17build1 on this machine.

Allow about ten minutes. You need a POSIX-style shell and a command name to investigate. The examples are ordinary, read-only commands. They do not need sudo, and this guide does not edit your shell configuration or system files.

1. Confirm the installed command

First check the command you are about to run and the package version. This avoids debugging a different implementation earlier in PATH:

$ command -v which
/usr/bin/which
$ dpkg-query -W -f='${Package} ${Version}\n' debianutils
debianutils 5.17build1

The package does not provide a useful --version response here. The installed program reports its usage and rejects that option, so use the package query when you need a version record.

Checkpoint

You should have an absolute path for which and a package version. If command -v which names a shell function or alias, inspect that first with your shell's normal function or alias tools. The rest of this guide describes the Debian executable, not a replacement wrapper.

2. Resolve one or more command names

Give which one or more names. It searches PATH for executable files and prints a pathname for each name it can resolve:

$ which sh printf
/usr/bin/sh
/usr/bin/printf

A pathname is useful evidence about the file selected by the current environment. It is not a promise that a shell command will behave exactly like that file: aliases, functions, built-ins and shell-specific command hashing are separate shell features.

which does not canonicalise pathnames. A result can therefore contain a symlink or a spelling inherited from PATH. If you need metadata about the selected file, inspect the result separately with commands such as ls -l or readlink.

3. Inspect every match with -a

Use -a when more than the first match matters. This is useful when an older system tool is shadowing a newer one:

$ which -a sh
/usr/bin/sh
/bin/sh

The order follows the search order. The first result is the first executable match found in PATH; later results show other matches. Seeing several files is not automatically a fault. Check which directory appears first, then decide whether that ordering is deliberate.

To make the cause visible, print the current search path:

$ printf '%s\n' "$PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Your value will differ. Do not copy the displayed path into a shell profile just because it appeared in an example. A PATH change affects every later command in that shell and can select an unexpected executable.

4. Test existence silently with -s

Use -s when a script needs the exit status rather than a pathname. It prints nothing and returns zero only when all supplied names are found and executable:

$ if which -s sh; then
>     printf '%s\n' 'sh is available'
> else
>     printf '%s\n' 'sh is missing'
> fi
sh is available
$ which -s definitely-not-a-command
$ printf 'status=%s\n' "$?"
status=1

With several names, one missing or non-executable name makes the result fail. That makes -s suitable for a simple prerequisite check:

$ if which -s awk sed; then
>     printf '%s\n' 'both tools are available'
> else
>     printf '%s\n' 'at least one tool is unavailable'
> fi

For portable shell scripts, consider the shell's command -v instead. It is a shell built-in or special command and can recognise commands that are not executable files on PATH, such as built-ins and functions. Use Debian's which when the question specifically concerns executable files found through PATH.

5. Reproduce PATH shadowing safely

When a tool behaves differently after an installation, test the search order in a temporary directory before changing anything permanent. This creates one harmless executable under /tmp and adds that directory only for two commands:

$ test_dir=$(mktemp -d)
$ printf '#!/bin/sh\necho test-tool\n' > "$test_dir/demo-tool"
$ chmod 755 "$test_dir/demo-tool"
$ PATH="$test_dir:$PATH" which demo-tool
/tmp/tmp.example/demo-tool
$ PATH="$test_dir:$PATH" which -a demo-tool
/tmp/tmp.example/demo-tool

The directory name is generated, so your output will not contain the literal /tmp/tmp.example. The temporary executable is first because the temporary directory was prepended to PATH. The assignment applies only to each command on those lines; it does not alter the parent shell's PATH.

Recovery

The example changes state only under /tmp. After checking the result, remove the temporary file and directory deliberately:

$ rm -- "$test_dir/demo-tool"
$ rmdir -- "$test_dir"

Do not replace $test_dir with a broad path. If rmdir says the directory is not empty, inspect it with find "$test_dir" -maxdepth 1 -mindepth 1 -print before removing anything else.

6. Read failures by their exit status

The Debian implementation documents three useful statuses:

  • 0: every specified command was found and executable;
  • 1: at least one command was missing or not executable;
  • 2: an invalid option was supplied.

For example, an unsupported option is a syntax error, not evidence that the command being searched for is absent:

$ which -z sh
Usage: /usr/bin/which [-as] args
Illegal option -z
$ printf 'status=%s\n' "$?"
status=2

Do not hide a non-zero status by piping the command into another tool before saving $?. In a script, test it immediately or use the if which -s ... form. If a lookup fails, check spelling, execute permission and the actual PATH before reaching for elevated privileges. sudo may use a different environment, so it can answer a different question.

Done means

  • You confirmed that which is the Debian executable and recorded the installed package version.
  • You resolved a command with the current PATH and know that the output is not canonicalised.
  • You used -a to investigate multiple matches when shadowing mattered.
  • You used -s and checked its status immediately for a quiet prerequisite test.
  • You know when command -v is a better shell-level check for aliases, functions and built-ins.
  • Any temporary PATH test has been removed, without changing persistent configuration.