检查命令是否有特定的命令行选项
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 -r
和 tac
都不可移植;您可能想出一个在 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 -rn2
和 tail -rn 2
在将它们传递给 tail
之前操纵的位置参数)。当缺少 tac
时,将 tac
作为函数实现会更容易。
有什么方法可以检查命令是否具有来自 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 -r
和 tac
都不可移植;您可能想出一个在 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 -rn2
和 tail -rn 2
在将它们传递给 tail
之前操纵的位置参数)。当缺少 tac
时,将 tac
作为函数实现会更容易。