Differences between revisions 7 and 8
Revision 7 as of 2007-10-11 14:23:06
Size: 3796
Editor: GreyCat
Comment: replace that horribly wrong example
Revision 8 as of 2008-05-22 22:21:49
Size: 3827
Editor: GreyCat
Comment: clean up a bit
Deletions are marked like this. Additions are marked like this.
Line 7: Line 7:
# This one works in bash # Bash
Line 18: Line 18:
# Also a bash solution # Bash
Line 26: Line 26:
Korn shell has {{{whence}}} instead: KornShell has {{{whence}}} instead:
Line 29: Line 29:
# Here's a ksh solution # ksh
Line 40: Line 40:
# Last resort -- using which(1) # Bourne. Last resort -- using which(1)
Line 72: Line 72:
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. 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.
Line 74: Line 74:
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. That should tell you how unreliable `which(1)` is. Here's a ''simplified'' version of such a test: 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:
Line 77: Line 77:
# Bourne

Anchor(faq81)

How can I determine whether a command exists anywhere in my PATH?

In BASH, there are a couple builtins that are suitable for this purpose: 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.

BashFAQ/081 (last edited 2023-05-22 10:02:19 by emanuele6)