12 SC2230
Joachim Ansorg edited this page 2021-11-12 19:52:28 +01:00

which is non-standard. Use builtin command -v instead.

This is an optional suggestion. It must be explicitly enabled with a directive enable=deprecate-which in a # shellcheck comment or .shellcheckrc

Problematic code:

which grep

Correct code:

# For the path of a single, unaliased, external command,
# or to check whether this will just "run" in this shell:
command -v grep
# To check whether commands exist, without obtaining a reusable path:
hash grep

Rationale:

which is a non-standard, external tool that locates an executable in PATH. command -v is a POSIX standard builtin, which uses the same lookup mechanism that the shell itself would.

Exceptions:

This check is opt-in only in 0.7.1+, and you may choose to ignore it in earlier versions. which is very common, and some prefer its executable-or-nothing behavior over command -v's handling of builtins, functions and aliases.

Caveats:

command -v does not check ALL parameters

command -v succeeds (with exit code 0) if any command exists:

# grep is in /usr/bin/grep
# foobar is not in path
#
$ command -v -- grep foobar; echo $?
0

In the above example, it should have failed and exited with 1 unless all commands exist, if it were to be a replacement for which. Other problems associated with command include its inclusion of builtins, aliases, and functions.

An alternative is:

$ hash <file1> <file2>

Which observes the standard behaviour of failures.

To obtain a path, type -p can be used instead. Like command -v, it has a similarly quirky behavior with builtins, aliases, and functions, although this is arguably milder since it would print nothing for these cases. The failure condition is similar to hash.