How do I test to see if an application exists in $PATH?

12,188

Solution 1

Use type commandname. This returns true if commandname is anything executable: alias, function, built-in or external command (looked up in $PATH). Alternatively, use command commandname which returns true if commandname is a built-in or external command (looked up in $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

There are a few sh variants (definitely pre-POSIX; I know of /bin/sh under OSF1 ≤3.x and some versions of the Almquist shell found in early NetBSD versions and a few 20th-century Linux distributions) where type always returns 0 or doesn't exist. I don't think any systems shipped with these this millennium. If you ever encounter them, here's a function you can use to search in $PATH manually:

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

This function is generally useful if you want to exclude built-ins and functions and look up the name in $PATH. Most shells have a built-in for this, command -v, though it's a relatively recent addition to POSIX (still optional as of POSIX:2004). It's basically a programmer-friendly version of type: it prints the full path for an executable in $PATH, the bare name for a built-in or function, and an alias definition for an alias.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash and zsh also have type -p to look up only executables in $PATH. Note that in bash, the return status of type -p foo is 0 if foo is a built-in or function; if you want to test for an executable in $PATH, you need to check that the output is not empty. type -p is not in POSIX; for instance Debian's ash (which is /bin/sh on Ubuntu) doesn't have it.

Solution 2

If you are only looking for external programs, you can also use which. Don't know how portable that is though.

Share:
12,188

Related videos on Youtube

xenoterracide
Author by

xenoterracide

Former Linux System Administrator, now full time Java Software Engineer.

Updated on September 17, 2022

Comments

  • xenoterracide
    xenoterracide almost 2 years

    I'm trying to write all of my sh startup/env scripts to work with as much DRY and as much: "works on every *nix I clone it to", as possible. This means making sure that if I try to run code that's not there, that the code fails gracefully. To that end I need to be able to test if programs exist. I know how to test if a file exists, but I'm not sure how to test to see if an application is executable within the path. I'd rather use the $PATH, as some of these need to work on arch, ubuntu, and centos. Some might be installed in my homedir, on systems where I don't have root, others might not be installed, and others yet my be installed in system paths.

  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 13 years
    @xenoterracide: Drop the brackets!
  • Steven D
    Steven D over 13 years
    I think you are looking for if type $APP >/dev/null 2>/dev/null; then ... You don't want the [].
  • Steven D
    Steven D over 13 years
    Bah, I knew I should have refreshed. Beaten by Gilles again!
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 13 years
    In theory, it's less portable than type or command; which is not in POSIX, for instance. In practice, which does exist almost everywhere, but in some places (where it's implemented as a csh script) it uses a different path (due to a .cshrc), which defeats the purpose.
  • ephemient
    ephemient over 13 years
    type -p if you're specifically looking for a command in $PATH (not aliases or functions or builtins).
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 13 years
    @ephemient: type -p isn't portable, and a bit strange in bash (see my edit).
  • Admin
    Admin about 2 years
    type -P in bash if specifically looking for a command in $PATH (not aliases or functions or builtins). Added in bash 2.05b. Admittedly, this isn't portable, which is what the OP wanted.