Size: 3827
Comment: clean up a bit
|
Size: 4037
Comment: command -v, for POSIX
|
Deletions are marked like this. | Additions are marked like this. |
Line 4: | Line 4: |
In BASH, there are a couple builtins that are suitable for this purpose: {{{hash}}} and {{{type}}}. Here's an example using {{{hash}}}: | The POSIX shell specifies a builtin called {{{command}}} which can be used for this purpose: {{{ # POSIX if command -v qwerty >/dev/null; then echo qwerty exists else echo qwerty does not exist fi }}} In BASH, there are a couple more builtins that may also be used: {{{hash}}} and {{{type}}}. Here's an example using {{{hash}}}: |
How can I determine whether a command exists anywhere in my PATH?
The POSIX shell specifies a builtin called command which can be used for this purpose:
# POSIX if command -v qwerty >/dev/null; then echo qwerty exists else echo qwerty does not exist fi
In BASH, there are a couple more builtins that may also be used: hash and type. Here's an example using hash:
# Bash if hash qwerty 2>/dev/null; then echo qwerty exists else echo qwerty does not exist fi
Or, if you prefer type:
# Bash if type -P qwerty >/dev/null; then echo qwerty exists else echo qwerty does not exist fi
KornShell has whence instead:
# ksh if whence -p qwerty >/dev/null; then echo qwerty exists else echo qwerty does not exist fi
If these builtins are not available (because you're in a Bourne shell, or whatever), then you may have to rely on the external command which (which is often a csh script, although sometimes a compiled binary). Unfortunately, which may not set a useful exit code, and it may not even write errors to stderr. In those cases, one must parse its output.
# Bourne. Last resort -- using which(1) tmpval=`LC_ALL=C which qwerty 2>&1` if test $rc -ne 0; then # FOR NOW, we'll assume that if this machine's which(1) sets a nonzero # exit status, that it actually failed. I've yet to see any case where # which(1) sets an erroneous failure -- just erroneous "successes". echo "qwerty is not installed. Please install it." else case "$tmpval" in *no\ *\ in\ *|*not\ found*|'') echo "qwerty is not installed. Please install it." ;; *) echo "Congratulations -- it seems you have qwerty (in $tmpval)." ;; esac fi
Note that which(1)'s output when a command is not found is not consistent across platforms. On HP-UX 10.20, for example, it prints no qwerty in /path /path /path ...; on OpenBSD 4.1, it prints qwerty: Command not found.; on Debian (3.1 and 4.0 at least) and SuSE, it prints nothing at all; on Red Hat 5.2, it prints which: no qwerty in (/path:/path:...); on Red Hat 6.2, it writes the same message, but on standard error instead of standard output; and on Gentoo, it writes something on stderr.
So our best portable solution is to match the words no and in, or the phrase not found, in the combined stdout + stderr and pray.
Note to the person who tried to put a function in this FAQ as a legacy Bourne shell example: legacy Bourne shells don't have functions, at all. POSIX shells have them, but the syntax is:
foo() { commands }
You may not use the word function, and you may especially not use the combination of the word function and the () symbols. No shell but bash accepts that. Also see BashPitfalls.
The approach used in configure scripts is usually to iterate over the components of $PATH and explicitly test for the presence of the command in each directory. The fact that this is preferred over which should tell you how unreliable which is. Here's a simplified version of such a test:
# Bourne save_IFS=$IFS IFS=: found=no for dir in $PATH; do if test -x "$dir/qwerty"; then echo "qwerty is installed (in $dir)" found=yes break fi done IFS=$save_IFS if test $found = no; then echo "qwerty is not installed" fi
Real configure scripts are generally much more complicated than this, since they may deal with systems where $PATH is not delimited by colons; or systems where executable programs may have optional extensions like .EXE; or $PATH variables that have the current working directory included in them as an empty string; etc. If you're interested in such things, I suggest reading an actual GNU autoconf-generated configure script. They're far too large and complicated to include in this FAQ.