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.
-
3This SO answer is the one I have bookmarked for such questions.– jw013Aug 29, 2012 at 22:10
-
mywiki.wooledge.org/BashFAQ/081– P iNov 11, 2020 at 14:06
2 Answers
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.
-
@gilles, will this (or something similar)
if [ type keychain ]; then
not work? I get error/home/xenoterracide/.zshrc:84: parse error: condition expected: type
I suppose I could write the function exists... I just thought this might be simpler in a sense... Dec 19, 2010 at 0:00 -
-
I think you are looking for
if type $APP >/dev/null 2>/dev/null; then ...
You don't want the[]
.– Steven DDec 19, 2010 at 0:05 -
4
-
type -p
if you're specifically looking for a command in$PATH
(not aliases or functions or builtins). Jan 8, 2011 at 6:34
If you are only looking for external programs, you can also use which. Don't know how portable that is though.
-
5In theory, it's less portable than
type
orcommand
;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. Dec 19, 2010 at 13:50