我希望能够从shell脚本判断任何POSIX系统上是否存在命令。
在Linux上,我可以执行以下操作:
if which <command>; then
...snip...
fi
但是,当命令不存在时,Solaris和MacOS which
不提供退出失败代码,它们只是向STDOUT打印错误消息。
另外,我最近发现which
命令本身不是POSIX(参见http://www.opengroup.org/onlinepubs/009695399/utilities/)
有什么想法吗?
答案 0 :(得分:22)
command -v
是一个POSIX指定的命令,可以执行的操作。
定义为在未找到命令或发生错误时返回&gt; 0.
答案 1 :(得分:2)
POSIX确实说,“If a command is not found, the exit status shall be 127.”所以你可以做到
<command>
if [ "${?}" = 127 ]; then
<handle not found>
fi
编写shell脚本时,通常需要一个bash shell(#!/bin/bash
),因为没有数组,几乎不可能正确地处理带空格的参数和/或文件名。在这种情况下,bash内置type -p
等同于它,因为它是内置的,它是可移植的。
答案 2 :(得分:0)
您可以将“which”的stdout / stderr读入变量或数组(使用反引号),而不是检查退出代码。
如果系统没有“which”或“where”命令,您还可以获取$ PATH变量的内容,然后遍历所有目录并搜索给定的可执行文件。这基本上是做什么的(尽管它可能会使用$ PATH结果的一些缓存/优化)。
答案 3 :(得分:0)
用于检查命令是否存在的 function_command_exists
:
#!/bin/sh
set -eu
function_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 usage
echo "example 1";
command="ls"
if function_command_exists "$command"; then
echo "Command: "\'$command\'" exists"
else
echo "Command: "\'$command\'" does not exist"
fi
command="notpresent"
if function_command_exists "$command"; then
echo "Command: "\'$command\'" exists"
else
echo "Command: "\'$command\'" does not exist"
fi
echo "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"
输出:
example 1
Command: 'ls' exists
Command: 'notpresent' does not exist
example 2
Command: 'ls' exists
End of the script
请注意,即使使用了脚本的 set -eu
选项,脚本也会执行到最后一行“脚本结束”
-e
中没有 Command: 'notpresent' does not exist
,因为 example 2
运算符因此跳过 &&
的执行,但脚本的执行会一直持续到结束。< /p>
请注意,echo "Command: "\'$command\'" does not exist"
不会检查您是否有权执行命令。这需要单独完成。
function_command_exists
的解决方案
command -v <command-to-check>
产生:
#!/bin/sh
set -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
因为在第一个示例中找到了 <handle not found 2>
。
运行 echo
并处理错误(包括找不到命令)的解决方案。
command
产生:
#!/bin/sh
set -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