views:

5159

answers:

9

How would I validate that a program exists? Which would then either return an error and exit or continue with the script.

It seems like it should be easy, but it's been stumping me.

+2  A: 

The which command might be useful. man which

It returns 0 if the executable is found, 1 if it's not found or not executable:

NAME

       which - locate a command

SYNOPSIS

       which [-a] filename ...

DESCRIPTION

       which returns the pathnames of the files which would be executed in the
       current environment, had its arguments been  given  as  commands  in  a
       strictly  POSIX-conformant  shell.   It does this by searching the PATH
       for executable files matching the names of the arguments.

OPTIONS

       -a     print all matching pathnames of each argument

EXIT STATUS

       0      if all specified commands are found and executable

       1      if one or more specified commands is  nonexistent  or  not  exe-
          cutable

       2      if an invalid option is specified

Nice thing about which is that it figures out if the executable is available in the environment that which is run in - saves a few problems...

Adam Davis
Use which if you looking for any executable named foo, but see my answer if you want to check a particular file /path/to/a/named/foo. Also note that which may not be available on some minimal systems, though it should be present on any full fledged installation...
dmckee
Don't rely in the exit status of which. Many operating systems have a which that doesn't even set an exit status other than 0.
lhunath
+3  A: 

Try using:

test -x filename

or

[ -x filename ]

From the bash manpage under "Conditional Expressions":

 -x file
          True if file exists and is executable.
dmckee
That means you need to already know the full path to the application.
lhunath
The OP didn't specify if he wanted to check for a specific instance or for any executable instance...I answered it the way I read it.
dmckee
+10  A: 

It depends whether you want to know whether it exists in one of the directories in the $PATH variable or whether you know the absolute location of it. If you want to know if it is in the $PATH variable, use

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

otherwise use

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

The redirection to /dev/null/ in the first example suppresses the output of the which program.

dreamlax
You really shouldn't be using "which" for the reasons outlined in my comment.
lhunath
+2  A: 

Why not use Bash builtins if you can?

which programname

...

type -P programname

+19  A: 

Yes; avoid "which". Not only is it an external process you're launching for doing very little (meaning builtins like "type" are way cheaper), you can also rely on the builtins to actually do what you want.

Why care?

  • Many operating systems have a "which" that doesn't even set an exit status, meaning the if which foo >/dev/null won't even work there and will always report that foo exists, even if it doesn't.
  • Many operating systems make which do custom and evil stuff like change the output or even hook into the package manager.

Don't use which. Instead use type.

$ type -P foo &>/dev/null || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }
lhunath
Geert
@Geert: The because that's convention. They both appear on your terminal, but standard error is definitely the preferred output for error messages and unexpected warnings.
lhunath
A: 

I never did get the above solutions to work on the box I have access to. For one, type has been installed (doing what more does). So the builtin directive is needed. This command works for me:

if [ builtin type -p vim ]; then echo "TRUE"; else echo "FALSE"; fi

+1  A: 

For those interested, none of the methodologies above work if you wish to detect an installed library. I imagine you are left either with physically checking the path (potentially for header files and such), or something like this (if you are on a Debian-based distro):

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

As you can see from the above, a "0" answer from the query means the package is not installed. This is a function of "grep" - a "0" means a match was found, a "1" means no match was found.

Nathan Crause
Agreed. This is the best solution here, since it works for libraries as well as programs.
mlissner
A: 

I had no success with this solution, I had to modify it a little:

dpkg --get-selections | grep -q linux-headers-$(uname -r)

if [ $? -eq 1 ]; then
        apt-get install linux-headers-$(uname -r)
fi
Jan
+1  A: 

I have a function defined in my .bashrc that makes this easier.

command_exists () {
    type "$1" &> /dev/null ;
}

Here's an example of how it's used (from my .bash_profile.)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi
Josh Strater