How would I validate that a program exists, in a way that will either return an error and exit, or continue with the script?
It seems like it should be easy, but it's been stumping me.
How would I validate that a program exists, in a way that will either return an error and exit, or continue with the script?
It seems like it should be easy, but it's been stumping me.
POSIX compatible:
command -v <the_command>
Example use:
if ! command -v <the_command> &> /dev/null
then
echo "<the_command> could not be found"
exit 1
fi
For Bash specific environments:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
Avoid which
. Not only is it an external process you're launching for doing very little (meaning builtins like hash
, type
or command
are way cheaper), you can also rely on the builtins to actually do what you want, while the effects of external commands can easily vary from system to system.
Why care?
which
that doesn't even set an exit status, meaning the if which foo
won't even work there and will always report that foo
exists, even if it doesn't (note that some POSIX shells appear to do this for hash
too).which
do custom and evil stuff like change the output or even hook into the package manager.So, don't use which
. Instead use one of these:
command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
(Minor side-note: some will suggest 2>&-
is the same 2>/dev/null
but shorter – this is untrue. 2>&-
closes FD 2 which causes an error in the program when it tries to write to stderr, which is very different from successfully writing to it and discarding the output (and dangerous!))
If your hash bang is /bin/sh
then you should care about what POSIX says. type
and hash
's exit codes aren't terribly well defined by POSIX, and hash
is seen to exit successfully when the command doesn't exist (haven't seen this with type
yet). command
's exit status is well defined by POSIX, so that one is probably the safest to use.
If your script uses bash
though, POSIX rules don't really matter anymore and both type
and hash
become perfectly safe to use. type
now has a -P
to search just the PATH
and hash
has the side-effect that the command's location will be hashed (for faster lookup next time you use it), which is usually a good thing since you probably check for its existence in order to actually use it.
As a simple example, here's a function that runs gdate
if it exists, otherwise date
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
}
You can use scripts-common to reach your need.
To check if something is installed, you can do:
checkBin <the_command> || errorMessage "This tool requires <the_command>. Install it please, and then run this tool again."
&>/dev/null
and >&2
parts are for? The line seems to work fine without them too. Thanks. –
Chelonian 2>&-
("close output file descriptor 2", which is stderr) has the same result as 2> /dev/null
; 2) >&2
is a shortcut for 1>&2
, which you may recognize as "redirect stdout to stderr". See the Advanced Bash Scripting Guide i/o redirection page for more info. –
Exhilarate command -v
returns true for functions. As such if you decided to wrap a program in a function with the same name, then you can't use command -v
to check if the program is installed. –
Criticism The following is a portable way to check whether a command exists in $PATH
and is executable:
[ -x "$(command -v foo)" ]
Example:
if ! [ -x "$(command -v git)" ]; then
echo 'Error: git is not installed.' >&2
exit 1
fi
The executable check is needed because bash returns a non-executable file if no executable file with that name is found in $PATH
.
Also note that if a non-executable file with the same name as the executable exists earlier in $PATH
, dash returns the former, even though the latter would be executed. This is a bug and is in violation of the POSIX standard. [Bug report] [Standard]
Edit: This seems to be fixed as of dash 0.5.11 (Debian 11).
In addition, this will fail if the command you are looking for has been defined as an alias.
.
, so that [ -x '' ]
may return true if the user has scan permission on the current directory; this leads to a false positive. (Fortunately this only affects a few older systems that are technically not POSIX compliant.) More resilient would be thing_path=$( command -v thing ) && [ -x "$thing_path" ]
–
Bourn [ -x "$(command -v echo)" ]; echo $?
prints 1! –
Foote test
also fails. –
Biotite I agree with lhunath to discourage use of which
, and his solution is perfectly valid for Bash users. However, to be more portable, command -v
shall be used instead:
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed. Aborting." >&2; exit 1; }
Command command
is POSIX compliant. See here for its specification: command - execute a simple command
Note: type
is POSIX compliant, but type -P
is not.
exit 1;
kills an xterm, if invoked from there. –
Palembang &>/dev/null
. However, I agree with you, what really matters is portability, I've edited my answer accordingly, now using standard sh redirect >/dev/null 2>&1
. –
Undermost then
for instance. See this answer if you require the executable to exist in $PATH
. –
Serilda It depends on 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.
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
&>
do? –
Markland &>
redirects both stdout and stderr together. –
Extractive &>
may not be available in your version of Bash. Marcello's code should work fine; it does the same thing. –
Extractive then
for instance. See this answer if you require the executable to exist in $PATH
. –
Serilda Expanding on @lhunath's and @GregV's answers, here's the code for the people who want to easily put that check inside an if
statement:
exists()
{
command -v "$1" >/dev/null 2>&1
}
Here's how to use it:
if exists bash; then
echo 'Bash exists!'
else
echo 'Your system does not have Bash'
fi
command
succeeds even for aliases, which might be somewhat counterintuitive. Checking for existence in an interactive shell will give different results from when you move it to a script. –
Flashcube shopt -u expand_aliases
ignores/hides aliases (like the alias ls='ls -F'
mentioned in another answer) and shopt -s expand_aliases
resolves them via command -v
. So perhaps it should be set prior to the check and unset after, though it could affect the function return value if you don't capture and return the output of the command call explicitly. –
Impromptu if exists conda; then
, even though anaconda is installed and returns: usage: conda [-h] [-V] command...
when one enters conda
in the terminal? (Note I verified your answer works with if exists bash; then
on an Ubuntu 20 OS.) –
Recalcitrant which conda
–
Kuhn command -v
displays also built-ins, functions and even keywords and returns 0 for those! –
Sophy Try using:
test -x filename
or
[ -x filename ]
From the Bash manpage under Conditional Expressions:
-x file True if file exists and is executable.
To use hash
, as @lhunath suggests, in a Bash script:
hash foo &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "foo not found."
fi
This script runs hash
and then checks if the exit code of the most recent command, the value stored in $?
, is equal to 1
. If hash
doesn't find foo
, the exit code will be 1
. If foo
is present, the exit code will be 0
.
&> /dev/null
redirects standard error and standard output from hash
so that it doesn't appear onscreen and echo >&2
writes the message to standard error.
if hash foo &> /dev/null; then ...
? –
Edwyna set -e
was set, the if...
part was never run. –
Sophy Command -v
works fine if the POSIX_BUILTINS option is set for the <command>
to test for, but it can fail if not. (It has worked for me for years, but I recently ran into one where it didn't work.)
I find the following to be more failproof:
test -x "$(which <command>)"
Since it tests for three things: path, existence and execution permission.
test -x $(which ls)
returns 0, as does test -x $(which sudo)
, even though ls
is installed and runnable and sudo
is not even installed within the docker container I'm running in. –
Traylor test -x "$(which <command>)"
–
Nickel ls
is aliased? I dont think it would work if the command has parameter. –
Zennie $ test -x $(which absent_cmd)
returns test: too many arguments
, while test -x "$(which absent_cmd)"
is properly parsed and results in exit code 1. –
Wilser test: too many arguments
suggests that which absent_cmd
returns a multi-word error message. An executable file having the same name as the message could exist. 😁 Using which
this way is just a bad idea. –
Flashcube If you check for program existence, you are probably going to run it later anyway. Why not try to run it in the first place?
if foo --version >/dev/null 2>&1; then
echo Found
else
echo Not found
fi
It's a more trustworthy check that the program runs than merely looking at PATH directories and file permissions.
Plus you can get some useful result from your program, such as its version.
Of course the drawbacks are that some programs can be heavy to start and some don't have a --version
option to immediately (and successfully) exit.
There are a ton of options here, but I was surprised no quick one-liners. This is what I used at the beginning of my scripts:
[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
This is based on the selected answer here and another source.
[[
and the command substitution are useless here. Simply command -v mvn || exit
will exit
if mvn
is not found; but then with that fixed this basically just repeats the accepted answer. –
Chelseychelsie It could be simpler, just:
#!/usr/bin/env bash
set -x
# if local program 'foo' returns 1 (doesn't exist) then...
if ! type -P foo; then
echo 'crap, no foo'
else
echo 'sweet, we have foo!'
fi
Change foo
to vi
to get the other condition to fire.
NOTE: always handle the negative cases first, like if !
. It's best to give the program every opportunity to fail; makes testing super easy ;-)
set -x
) –
Sophy set -x
is the bash debugger. it helps to illustrate what's going on when people just copy/paste->execute a solution from sites like this; that's all. Comment/delete the line if you're done debugging. –
Erie Check for multiple dependencies and inform status to end users
for cmd in latex pandoc; do
printf '%-10s' "$cmd"
if hash "$cmd" 2>/dev/null; then
echo OK
else
echo missing
fi
done
Sample output:
latex OK
pandoc missing
Adjust the 10
to the maximum command length. It is not automatic, because I don't see a non-verbose POSIX way to do it:
How can I align the columns of a space separated table in Bash?
Check if some apt
packages are installed with dpkg -s
and install them otherwise.
See: Check if an apt-get package is installed and then install it if it's not on Linux
It was previously mentioned at: How can I check if a program exists from a Bash script?
column -t
(part of util-linux). –
Johm I never did get the previous answers 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
if
syntax, simply use if builtin type -p vim; then ...
. And the backticks are really ancient and deprecated syntax, $()
is supported even by sh
on all modern systems. –
Munsey builtin type -p if
outputs nothing and returns 0 whether or not if
exists. –
Sophy if builtin type -p if
or if [ `builtin type -p if` ]
, except the latter is unnecessarily verbose and uses deprecated syntax. –
Munsey if
. –
Sophy I wanted the same question answered but to run within a Makefile.
install:
@if [[ ! -x "$(shell command -v ghead)" ]]; then \
echo 'ghead does not exist. Please install it.'; \
exit -1; \
fi
[[
. –
Flashcube $(shell ...)
within a recipe is almost always wrong. The accepted answer will work fine in a Makefile
, too. exit -1
is not well-defined and the conditional is useless anyway. –
Chelseychelsie hash foo 2>/dev/null
: works with Z shell (Zsh), Bash, Dash and ash.
type -p foo
: it appears to work with Z shell, Bash and ash (BusyBox), but not Dash (it interprets -p
as an argument).
command -v foo
: works with Z shell, Bash, Dash, but not ash (BusyBox) (-ash: command: not found
).
Also note that builtin
is not available with ash and Dash.
command -v foo
works on busybox sh
(BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)). It fails correctly with 127 when foo is not found and prints the path if it finds it. –
Batton type -p if
does not work. –
Sophy zsh
only, but very useful for zsh
scripting (e.g. when writing completion scripts):
The zsh/parameter
module gives access to, among other things, the internal commands
hash table. From man zshmodules
:
THE ZSH/PARAMETER MODULE
The zsh/parameter module gives access to some of the internal hash ta‐
bles used by the shell by defining some special parameters.
[...]
commands
This array gives access to the command hash table. The keys are
the names of external commands, the values are the pathnames of
the files that would be executed when the command would be in‐
voked. Setting a key in this array defines a new entry in this
table in the same way as with the hash builtin. Unsetting a key
as in `unset "commands[foo]"' removes the entry for the given
key from the command hash table.
Although it is a loadable module, it seems to be loaded by default, as long as zsh
is not used with --emulate
.
example:
martin@martin ~ % echo $commands[zsh]
/usr/bin/zsh
To quickly check whether a certain command is available, just check if the key exists in the hash:
if (( ${+commands[zsh]} ))
then
echo "zsh is available"
fi
Note though that the hash will contain any files in $PATH
folders, regardless of whether they are executable or not. To be absolutely sure, you have to spend a stat
call on that:
if (( ${+commands[zsh]} )) && [[ -x $commands[zsh] ]]
then
echo "zsh is available"
fi
The which
command might be useful. man which
It returns 0 if the executable is found and returns 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 executable
2 if an invalid option is specified
The nice thing about which
is that it figures out if the executable is available in the environment that which
is run in - it saves a few problems...
For those interested, none of the methodologies in previous answers 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 distribution):
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.
cmd; if [ $? -eq 0 ]; then
should be refactored to if cmd; then
–
Chelseychelsie dpkg
or apt
–
Kerwon Use Bash builtins if you can:
which programname
...
type -P programname
which
is not a Bash builtin. –
Chelseychelsie -P
isn't POSIX. Why is type -P
preferred? –
Irk This will tell according to the location if the program exist or not:
if [ -x /usr/bin/yum ]; then
echo "This is Centos"
fi
I'd say there isn't any portable and 100% reliable way due to dangling alias
es. For example:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
Of course, only the last one is problematic (no offence to Ringo!). But all of them are valid alias
es from the point of view of command -v
.
In order to reject dangling ones like ringo
, we have to parse the output of the shell built-in alias
command and recurse into them (command -v
isn't a superior to alias
here.) There isn't any portable solution for it, and even a Bash-specific solution is rather tedious.
Note that a solution like this will unconditionally reject alias ls='ls -F'
:
test() { command -v $1 | grep -qv alias }
shopt -u expand_aliases
ignores/hides these aliases and shopt -s expand_aliases
shows them via command -v
. –
Impromptu If you guys/gals can't get the things in answers here to work and are pulling hair out of your back, try to run the same command using bash -c
. Just look at this somnambular delirium. This is what really happening when you run $(sub-command):
First. It can give you completely different output.
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls
Second. It can give you no output at all.
$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
.bashrc
have a [ -z "$PS1" ] && return
prepended by # If not running interactively, don't do anything
so I guess that is a reason why even explicit sourcing of bashrc in non-interactive mode doesn't help. The problem can be workarounded by calling a script with a ss64.com/bash/source.html dot operator . ./script.sh
but that is not a thing one would like to remember to type each time. –
Choli #!/bin/bash
a=${apt-cache show program}
if [[ $a == 0 ]]
then
echo "the program doesn't exist"
else
echo "the program exists"
fi
#program is not literal, you can change it to the program's name you want to check
apt-cache
is not a standard utility, and only exists on Debian-based distributions. Why is testing ”$?” to see if a command succeeded or not, an anti-pattern? –
Chelseychelsie I had to check if Git was installed as part of deploying our CI server. My final Bash script was as follows (Ubuntu server):
if ! builtin type -p git &>/dev/null; then
sudo apt-get -y install git-core
fi
sudo
: without the conditional, it would always stop and ask for password (unless you did a sudo recently). BTW, it may be useful to do sudo -p "Type your password to install missing git-core: "
so the prompt doesn't come out of the blue. –
Edwyna To mimic Bash's type -P cmd
, we can use the POSIX compliant env -i type cmd 1>/dev/null 2>&1
.
man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.
ls() { echo 'Hello, world!'; }
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
type
seems to be a builtin
in most shells so this can't work because env
uses execvp
to run command
so command
cannot be a builtin
(and the builtin
will always be run within the same environment). This fails for me in bash
, ksh93
, zsh
, busybox [a]sh
and dash
all of which provide type
as a shell builtin. –
Aquila The hash-variant has one pitfall: On the command line you can for example type in
one_folder/process
to have process executed. For this the parent folder of one_folder must be in $PATH. But when you try to hash this command, it will always succeed:
hash one_folder/process; echo $? # will always output '0'
$PATH
"—This is completely inaccurate. Try it. For this to work, one_folder must be in the current directory. –
Jurat I second the use of "command -v". E.g. like this:
md=$(command -v mkdirhier) ; alias md=${md:=mkdir} # bash
emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs
If there isn't any external type
command available (as taken for granted here), we can use POSIX compliant env -i sh -c 'type cmd 1>/dev/null 2>&1'
:
# Portable version of Bash's type -P cmd (without output on stdout)
typep() {
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1" || exit 1
}
# Get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
At least on Mac OS X v10.6.8 (Snow Leopard) using Bash 4.2.24(2) command -v ls
does not match a moved /bin/ls-temp
.
My setup for a Debian server:
I had the problem when multiple packages contained the same name.
For example apache2
. So this was my solution:
function _apt_install() {
apt-get install -y $1 > /dev/null
}
function _apt_install_norecommends() {
apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
echo "Package is available : $1"
PACKAGE_INSTALL="1"
else
echo "Package $1 is NOT available for install"
echo "We can not continue without this package..."
echo "Exitting now.."
exit 0
fi
}
function _package_install {
_apt_available $1
if [ "${PACKAGE_INSTALL}" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install $1
sleep 0.5
fi
fi
}
function _package_install_no_recommends {
_apt_available $1
if [ "${PACKAGE_INSTALL}" = "1" ]; then
if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
echo "package is already_installed: $1"
else
echo "installing package : $1, please wait.."
_apt_install_norecommends $1
sleep 0.5
fi
fi
}
In case you want to check if a program exists and is really a program, not a Bash built-in command, then command
, type
and hash
are not appropriate for testing as they all return 0 exit status for built-in commands.
For example, there is the time program which offers more features than the time built-in command. To check if the program exists, I would suggest using which
as in the following example:
# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
echo "The time program does not exist on this system."
exit 1
fi
# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
hash
telling wrong that there exists an executable by the name of the given argument? –
Sophy Script
#!/bin/bash
# Commands found in the hash table are checked for existence before being
# executed and non-existence forces a normal PATH search.
shopt -s checkhash
function exists() {
local mycomm=$1; shift || return 1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
readonly -f exists
exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'
Result
✘ [ABRT]: notacmd: command does not exist
hits command
0 /usr/bin/bash
Fin.
Assuming you are already following safe shell practices:
set -eu -o pipefail
shopt -s failglob
./dummy --version 2>&1 >/dev/null
This assumes the command can be invoked in such a way that it does (almost) nothing, like reporting its version or showing help.
If the dummy
command is not found, Bash exits with the following error...
./my-script: line 8: dummy: command not found
This is more useful and less verbose than the other command -v
(and similar) answers because the error message is auto generated and also contains a relevant line number.
dummy
's existence is out of hands of the script's author. Also, it lacks explanation of how it works and that it changes settings of the execution environment. –
Flashcube shopt
call can be replaced with POSIX set -f
, which is shorter and portable. The pipefail option is not supported in POSIX, though, and there is no alternative, AFAIK. –
Flashcube Late answer but this is what I ended up doing.
I just check if the command I execute returns an error code. If it returns 0 it means program is installed. Moreover you can use this to check the output of a script. Take for instance this script.
foo.sh
#!/bin/bash
echo "hello world"
exit 1 # throw some error code
Examples:
# outputs something bad... and exits
bash foo.sh $? -eq 0 || echo "something bad happened. not installed" ; exit 1
# does NOT outputs nothing nor exits because dotnet is installed on my machine
dotnet --version $? -eq 0 || echo "something bad happened. not installed" ; exit 1
Basically all this is doing is checking the exit code of a command run. the most accepted answer on this question will return true even if the command exit code is not 0.
command
with the flag -v
to quickly validate if its argument is a built-in or executable command that is found in PATH
. So the statement if ! command -v STRING; then ...; fi
will validate if STRING
is a valid command. –
Emission false
which returns a nonzero error code by design. –
Chelseychelsie checkexists() {
while [ -n "$1" ]; do
[ -n "$(which "$1")" ] || echo "$1": command not found
shift
done
}
GIT=/usr/bin/git # STORE THE RELATIVE PATH
# GIT=$(which git) # USE THIS COMMAND TO SEARCH FOR THE RELATIVE PATH
if [[ ! -e $GIT ]]; then # CHECK IF THE FILE EXISTS
echo "PROGRAM DOES NOT EXIST."
exit 1 # EXIT THE PROGRAM IF IT DOES NOT
fi
# DO SOMETHING ...
exit 0 # EXIT THE PROGRAM IF IT DOES
/usr/local/bin
instead and your code would exit. –
Vulture I couldn't get one of the solutions to work, but after editing it a little I came up with this. Which works for me:
dpkg --get-selections | grep -q linux-headers-$(uname -r)
if [ $? -eq 1 ]; then
apt-get install linux-headers-$(uname -r)
fi
dpkg
or apt
. –
Kerwon I use this, because it's very easy:
if [ $(LANG=C type example 2>/dev/null | wc -l) = 1 ]; then
echo exists;
else
echo "not exists";
fi
or
if [ $(LANG=C type example 2>/dev/null | wc -l) = 1 ]; then
echo exists
else
echo "not exists"
fi
It uses shell builtins and programs' echo status to standard output and nothing to standard error. On the other hand, if a command is not found, it echos status only to standard error.
type
is (almost) fine, but the pretzel logic to check its result is probably what caused the downvotes here. See #36371721 –
Chelseychelsie I would just try and call the program with for example --version
or --help
and check if the command succeeded or failed
Used with set -e
, the script will exit if the program is not found, and you will get a meaningful error message:
#!/bin/bash
set -e
git --version >> /dev/null
--version
or --help
option. –
Larrylars © 2022 - 2024 — McMap. All rights reserved.
which
returns true for these.type
without arguments will additionally return true for reserved words and shell builtins. If "program" means "excutable in$PATH
", then see this answer. – Serildawhich
you are using; which is not provided by Bash, but it is by e.g. Debian's debianutils. – Sophytype
would be preferable overwhich
, since we know that it is available. Howeever, bothtype
andwhich
do not detect, whether a program exists, but whether is is found in the PATH. To see whether a program of a certain name "exists" in a file system, you would have to usefind
. – Thorathoracic