Checking for Program Existence in Bash Scripts
When writing Bash scripts, it’s often necessary to verify that a required program is installed and available before proceeding. This ensures your script doesn’t fail unexpectedly due to a missing dependency. Several methods can accomplish this, each with its own trade-offs regarding portability and reliability. This tutorial will explore the most effective approaches.
Why Avoid which?
Historically, the which command was used to locate executable files in the user’s PATH environment variable. However, it’s generally discouraged for use in scripts. Here’s why:
- Inconsistent Behavior: The behavior of
whichcan vary across different operating systems and distributions. - Missing Exit Status: Some implementations of
whichdon’t reliably set an exit status, making it difficult to determine success or failure within a script’s conditional logic. - External Process: Launching an external process like
whichis less efficient than using Bash built-ins.
Using command -v (Recommended)
The most portable and reliable method is to use the command -v built-in. This command searches for a command in the PATH and returns its path if found. Importantly, it does set an appropriate exit status.
Here’s how it works:
command -v <command_name>
If <command_name> is found, command -v will output the full path to the executable and return an exit code of 0 (success). If not found, it returns an exit code of 1 (failure).
To use this in a script, combine it with a conditional statement:
if ! command -v git 2> /dev/null; then
echo "Error: git is not installed." >&2
exit 1
fi
# Continue with the script if git is found
echo "git is installed. Proceeding..."
Explanation:
! command -v git: This inverts the exit status ofcommand -v git. So, ifgitis not found, theifcondition becomes true.2> /dev/null: This redirects standard error (file descriptor 2) to/dev/null, suppressing any error messages thatcommand -vmight produce. This keeps your script’s output clean.>&2: This redirects standard output to standard error. Used to print the error message to stderr.exit 1: Ifgitis not found, the script exits with an error code of 1.
Using [ -x "$(command -v <command_name>)" ] (Checking Executability)
This method builds upon the previous one and also verifies that the found file is actually executable. This is important because a file with the same name as a command might exist but not be executable.
if [ -x "$(command -v git)" ]; then
echo "git is installed and executable."
else
echo "git is either not installed or not executable."
exit 1
fi
Explanation:
$(command -v git): This executescommand -v gitand captures its output (the path to the executable, if found).[ -x ... ]: This is a conditional expression that checks if the file at the given path is executable. The-xoption specifically tests for executability.
Using type (Bash Specific)
If your script is specifically designed for Bash, you can use the type command. type provides information about commands, including whether they are built-ins, aliases, or external commands.
if type gdate > /dev/null 2>&1; then
echo "gdate is available."
else
echo "gdate is not available."
fi
Explanation:
type gdate: This checks ifgdateis defined as a command, built-in, alias, etc.> /dev/null 2>&1: This redirects both standard output and standard error to/dev/null, suppressing any output fromtype.
While convenient, remember that type is not a POSIX standard command and might not be available in all shells.
Using hash (Bash Specific)
The hash command checks if a command is already hashed (i.e., its location is known). If it’s not hashed, it can be used to attempt to locate the command.
if hash gdate 2>/dev/null; then
echo "gdate is available (or already hashed)."
else
echo "gdate is not available."
fi
Important Considerations:
- Portability:
command -vis the most portable option as it’s part of the POSIX standard. - Executability: Always consider checking for executability (
-x) to ensure the found file can actually be run. - Built-ins vs. External Commands:
typeandhashare helpful for distinguishing between built-in commands and external programs. - Error Handling: Always include appropriate error handling and exit codes to ensure your script behaves gracefully when a required program is missing.