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.
#!/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?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.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.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.false which returns a nonzero error code by design.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.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 stackoverflow.com/questions/36371221/…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.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.
whichreturns true for these.typewithout arguments will additionally return true for reserved words and shell builtins. If "program" means "excutable in$PATH", then see this answer.whichyou are using; which is not provided by Bash, but it is by e.g. Debian's debianutils.typewould be preferable overwhich, since we know that it is available. Howeever, bothtypeandwhichdo 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.