hel*_*hod 45 bash options shell-script user-interface getopts
目前我正在编写一个 Bash 脚本,它具有以下要求:
我知道这getopts将是可移植性方面的首选方式,但 AFAIK 它不支持长选项。
getopt支持长选项,但BashGuide强烈建议反对它:
永远不要使用 getopt(1)。getopt 无法处理空参数字符串或带有嵌入空格的参数。请忘记它曾经存在过。
因此,仍然可以选择手动解析。这很容易出错,会产生相当多的样板代码,而且我需要自己处理错误(我想自己getopt(s)进行错误处理)。
那么,在这种情况下,首选是什么?
l0b*_*0b0 28
getoptvsgetopts似乎是一个宗教问题。至于反对的论点getopt在猛砸常见问题:
“getopt无法处理空参数字符串”似乎指的是可选参数的已知问题,它看起来getopts根本不支持(至少从help getoptsBash 4.2.24 的阅读来看)。来自man getopt:
getopt(3) 可以解析带有可选参数的长选项,这些可选参数被赋予一个空的可选参数(但对于短选项不能这样做)。此 getopt(1) 将空的可选参数视为不存在。
我不知道“getopt无法处理带有嵌入空格的 [...] 参数”来自哪里,但让我们测试一下:
测试.sh:
#!/usr/bin/env bash
set -o errexit -o noclobber -o nounset -o pipefail
params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")"
eval set -- "$params"
while true
do
case "$1" in
-a|--alpha)
echo alpha
shift
;;
-b|--bravo)
echo "bravo=$2"
shift 2
;;
-c|--charlie)
echo charlie
shift
;;
--)
shift
break
;;
*)
echo "Not implemented: $1" >&2
exit 1
;;
esac
done
Run Code Online (Sandbox Code Playgroud)跑:
$ ./test.sh -
$ ./test.sh -acb ' whitespace FTW '
alpha
charlie
bravo= whitespace FTW
$ ./test.sh -ab '' -c
alpha
bravo=
charlie
$ ./test.sh --alpha --bravo ' whitespace FTW ' --charlie
alpha
bravo= whitespace FTW
charlie
Run Code Online (Sandbox Code Playgroud)对我来说看起来像是 check and mate,但我相信有人会告诉我我是如何完全误解这句话的。当然,便携性问题仍然存在;您必须决定在具有较旧或没有 Bash 的平台上投入多少时间是值得的。我自己的建议是使用YAGNI和KISS指南 - 仅针对您知道将要使用的特定平台进行开发。随着开发时间的延长,Shell 代码的可移植性通常会达到 100%。
Sté*_*las 12
有这个getopts_long编写为 POSIX shell 函数,您可以将其嵌入脚本中。
请注意,Linux getopt(来自util-linux)在非传统模式下可以正常工作并支持长选项,但如果您需要移植到其他 Unices,则可能不适合您。
最新版本的 ksh93 ( getopts) 和 zsh ( zparseopts) 内置支持解析长选项,这可能是您的一个选项,因为它们可用于大多数 Unices(尽管默认情况下通常未安装)。
另一种选择是使用perl和它的Getopt::Long模块,这两者在当今大多数 Unices 上都应该可用,要么通过编写整个脚本,perl要么只是调用 perl 来解析选项并将提取的信息提供给 shell。就像是:
parsed_ops=$(
perl -MGetopt::Long -le '
@options = (
"foo=s", "bar", "neg!"
);
Getopt::Long::Configure "bundling";
$q="'\''";
GetOptions(@options) or exit 1;
for (map /(\w+)/, @options) {
eval "\$o=\$opt_$_";
$o =~ s/$q/$q\\$q$q/g;
print "opt_$_=$q$o$q"
}' -- "$@"
) || exit
eval "$parsed_ops"
# and then use $opt_foo, $opt_bar...
Run Code Online (Sandbox Code Playgroud)
查看perldoc Getopt::Long它可以做什么以及它与其他选项解析器的不同之处。
von*_*and 11
如果它必须可移植到一系列 Unices,则必须坚持使用 POSIX sh。和 AFAIU 在那里,您别无选择,只能手动滚动参数处理。