找出POSIX系统上是否存在命令

时间:2009-04-18 00:31:34

标签: unix shell posix

我希望能够从shell脚本判断任何POSIX系统上是否存在命令。

在Linux上,我可以执行以下操作:

if which <command>; then
   ...snip...
fi

但是,当命令不存在时,Solaris和MacOS which不提供退出失败代码,它们只是向STDOUT打印错误消息。

另外,我最近发现which命令本身不是POSIX(参见http://www.opengroup.org/onlinepubs/009695399/utilities/

有什么想法吗?

4 个答案:

答案 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