Find out if a command exists on POSIX system
You could read the stdout/stderr of "which" into a variable or an array (using backticks) rather than checking for an exit code.
If the system does not have a "which" or "where" command, you could also grab the contents of the $PATH variable, then loop over all the directories and search for the given executable. That's essentially what which does (although it might use some caching/optimization of $PATH results).
A function_command_exists
for checking if a command exists:
#!/bin/shset -eufunction_command_exists() { local command="$1" local IFS=":" # paths are delimited with a colon in $PATH # iterate over dir paths having executables for search_dir in $PATH do # seek only in dir (excluding subdirs) for a file with an exact (case sensitive) name found_path="$(find "$search_dir" -maxdepth 1 -name "$command" -type f 2>/dev/null)" # (positive) if a path to a command was found and it was executable test -n "$found_path" && \ test -x "$found_path" && \ return 0 done # (negative) if a path to an executable of a command was not found return 1}# example usageecho "example 1";command="ls"if function_command_exists "$command"; then echo "Command: "\'$command\'" exists"else echo "Command: "\'$command\'" does not exist"ficommand="notpresent"if function_command_exists "$command"; then echo "Command: "\'$command\'" exists"else echo "Command: "\'$command\'" does not exist"fiecho "example 2";command="ls"function_command_exists "$command" && echo "Command: "\'$command\'" exists"command="notpresent"function_command_exists "$command" && echo "Command: "\'$command\'" does not exist"echo "End of the script"
output:
example 1Command: 'ls' existsCommand: 'notpresent' does not existexample 2Command: 'ls' existsEnd of the script
Note that even the set -eu
that turns -e
option for the script was used the script was executed to the last line "End of the script"
There is no Command: 'notpresent' does not exist
in the example 2
because of the &&
operator so the execution of echo "Command: "\'$command\'" does not exist"
is skipped but the execution of the script continues till the end.
Note that the function_command_exists
does not check if you have a right to execute the command. This needs to be done separately.
Solution with command -v <command-to-check>
#!/bin/shset -eu;# check if a command exists (Yes)command -v echo > /dev/null && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 1>"fi# check if a command exists (No)command -v command-that-does-not-exists > /dev/null && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 2>"fi
produces:
<handle not found 2>
because echo
was found at the first example.
Solution with running a command
and handling errors including command not found.
#!/bin/shset -eu;# check if a command exists (No)command -v command-that-does-not-exist > /dev/null && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 2>"fi# run command and handle errors (no problem expected, echo exist)echo "three" && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 3>"elif [ "${status}" -ne 0 ]; then echo "<handle other error 3>"fi# run command and handle errors (<handle not found 4> expected)command-that-does-not-exist && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 4>"elif [ "${status}" -ne 0 ]; then echo "<handle other error 4>"fi# run command and handle errors (command exists but <handle other error 5> expected)ls non-existing-path && status="$?" || status="$?"if [ "${status}" = 127 ]; then echo "<handle not found 5>"elif [ "${status}" -ne 0 ]; then echo "<handle other error 5>"fi
produces:
<handle not found 2>three./function_command_exists.sh: 34: ./function_command_exists.sh: command-that-does-not-exist: not found<handle not found 4>ls: cannot access 'non-existing-path': No such file or directory<handle other error 5>