检查命令是否有特定的命令行选项

check whether command has a specific command line option

有什么方法可以检查命令是否具有来自 shell 脚本的特定命令行选项?

我的用例是 tail 命令。在 tail 的 BSD 版本中,它具有 -r(反向)选项。此选项在 GNU 版本中不可用

我可以从 shell 脚本中进行检查以仅将此选项用于 MacOS,并将 tac 用于 Linux。但问题是人们也可以在 MacOS 中安装 tail 的 GNU 版本。所以更好的解决办法是检查命令是否有-r选项。

这是一般情况下不可能解决的问题;如果有人将不同的程序安装为 tail 或别名或 shell 改变其行为的函数,会发生什么情况?您在这里发现制作 portable/reliable shell 脚本(特别是在非常不同的操作系统之间)可能非常困难。你必须自己决定如何做出所有这些决定以及你想在哪里划清界限。

快速而肮脏的方法就是用一些已知的输入调用 tail -r 并查看输出是否符合您的预期。使用它来决定稍后在脚本中做什么。一个例子(可能不是防弹的):

#!/bin/bash

INPUT=$(mktemp)
OUTPUT=$(mktemp)
COMPARE=$(mktemp)

cat >${INPUT} <<EOF
1
2
3
EOF

cat >${COMPARE} <<EOF
3
2
1
EOF

tail -r ${INPUT} >${OUTPUT} 2>&1

cmp -s ${OUTPUT} ${COMPARE}
if [ $? == 0 ]
then
    echo "'tail -r' behaves as expected"
else
    echo "'tail -r' does not behave as expected"
fi

rm ${INPUT} ${OUTPUT} ${COMPARE}

它在我刚测试过的 Mac 和 Linux 机器上按预期输出。

tail -rtac 都不可移植;您可能想出一个在 BSD 和 GNU 中都可以工作但在其他系统上可能会失败的解决方案。因此,在 awk 中实现相同的功能并改为使用它。喜欢:

awk '{buf[NR]=[=10=]} END{for(i=NR;i>0;i--)print buf[i]}'

这将适用于所有 POSIX awk。

-r-c-n 的结合也可以通过管道 tail 到上述命令来模拟。 -r-b 可能有点挑战,但并非不可能。

如果在环境中找到的实用程序不能满足您的要求,常用技术是定义函数。类似于:

expect=$'2\n1'
if ! test "$(printf '1\n2\n' | tail -r)" = "$expect"; then
        tail() { if test "" = "-r"; then shift; command tail "$@" | tac;
                else command tail "$@"; fi; }
fi

在这种特殊情况下,上述功能不正确,因为您需要实现完整的选项解析以提供所需的功能(例如,需要解析 tail -rn2tail -rn 2在将它们传递给 tail 之前操纵的位置参数)。当缺少 tac 时,将 tac 作为函数实现会更容易。