我刚刚发现 getopt
不是跨平台的(特别是对于 FreeBSD 和 Linux)。此问题的最佳解决方法是什么?
最佳答案
getopt
命令基本上有两个版本:原始版本和 GNU 增强版本。 GNU 增强版向后兼容原始版本,因此如果您只使用原始版本的功能,它也适用于两个版本。
检测可用的getopt版本
如果 GNU 增强版可用,您可以检测哪个版本可用并使用增强功能,如果 GNU 增强版不可用,您可以限制自己使用原始功能。增强版有一个 -T
选项,用于测试哪个版本可用。
getopt -T > /dev/null
if [ $? -eq 4 ]; then
# GNU enhanced getopt is available
set -- `getopt --long help,output:,version --options ho:v -- "$@"`
else
# Original getopt is available
set -- `getopt ho:v "$@"`
fi
考虑使用内置的 shell 命令 getopts
(带有“s”),因为它更便携。但是,getopts
不支持长选项(例如 --help
)。
如果你喜欢长选项,就用getopt
,用上面的测试看看有没有GNU增强版的getopt
。如果增强版本不可用,脚本可以优雅地降级为使用 getopt
的原始版本(不支持长选项名称且不支持空格)或使用 getopts
(不支持长选项名称)。
正确使用GNU增强的getopt
让 GNU 增强版正确处理带有空格的参数是很棘手的。这是如何完成的:
ARGS=`getopt --long help,output:,verbose --options ho:v -- "$@"`
if [ $? -ne 0 ]; then
echo "Usage error (use -h for help)" >&2
exit 2
fi
eval set -- $ARGS
# Parameters are now sorted: options appear first, followed by --, then arguments
# e.g. entering: "foo bar" -o abc baz -v
# produces: -o 'abc' -v -- 'foo bar' 'baz'
秘诀是在双引号非常重要的地方(第 1 行)使用 "$@"
,并eval
集合 命令(第 6 行)。
因此可以检测和处理 getopt
引发的错误,对 getopt
的调用与 eval
分开完成,两者由ARGS 变量。
完整的工作示例
PROG=`basename $0`
getopt -T > /dev/null
if [ $? -eq 4 ]; then
# GNU enhanced getopt is available
ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "$@"`
else
# Original getopt is available (no long option names, no whitespace, no sorting)
ARGS=`getopt ho:v "$@"`
fi
if [ $? -ne 0 ]; then
echo "$PROG: usage error (use -h for help)" >&2
exit 2
fi
eval set -- $ARGS
while [ $# -gt 0 ]; do
case "$1" in
-h | --help) HELP=yes;;
-o | --output) OUTFILE="$2"; shift;;
-v | --verbose) VERBOSE=yes;;
--) shift; break;; # end of options
esac
shift
done
if [ $# -gt 0 ]; then
# Remaining parameters can be processed
for ARG in "$@"; do
echo "$PROG: argument: $ARG"
done
fi
echo "$PROG: verbose: $VERBOSE"
echo "$PROG: output: $OUTFILE"
echo "$PROG: help: $HELP"
这个例子可以从https://gist.github.com/hoylen/6607180下载
Wikipedia's entry on getopts上的对比表比较不同的特征。
关于bash - shell脚本的跨平台getopt,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2721946/