【发布时间】:2018-03-30 12:25:22
【问题描述】:
我一直在学习命令行参数解析。关于这个已经有很长的话题了,我不想在这里挑衅:
Using getopts in bash shell script to get long and short command line options
How do I parse command line arguments in Bash?
使用getopts,如果你想解析一个参数/值对,比如“--opt value”,一种方法是让getopts把它当作一个名为“-”的参数,值变成“-opt”。然后我们解析它并通过符号${!OPTIND} 获取用户值。我需要了解更多。
在我上面引用的第一个线程中,使用了${!OPTIND},有人说“那是什么?”答案是“它是间接替代”。看了关于间接引用的注释,特别是https://unix.stackexchange.com/questions/41292/variable-substitution-with-an-exclamation-mark-in-bash和http://mywiki.wooledge.org/BashFAQ/006,我大致理解了间接引用,但我不理解${!OPTIND}作为它的例子。
$OPTIND 的值是一个整数,是下一个命令行参数的索引。它不是另一个数组中的值。
在上面的 BashFAQ/006 链接中,有关于间接的警告和不使用它的一般建议。也许这没什么大不了的,但我想尽可能地避免危险。
我们可以避免间接吗?似乎我应该能够只使用${OPTIND} 作为整数从$@、$@[$OPTIND]} 中获取值。
如果您需要示例,这是一个我称为“cli-6.sh”的脚本,它将接收不带等号的长格式参数。像这样运行:
$ ./cli-6.sh -v --fred good --barney bad --wilma happy
省略 -v 以减少冗长。
$ ./cli-6.sh --fred good --barney bad --wilma happy
After Parsing values, ordinary getopts
VERBOSE 0
Arrays of opts and values
optary: fred barney wilma
valary: good bad happy
希望这也适合你 :) 我没有使用关联数组来保存这些值,因为我希望这最终能在其他 shell 中工作。
#/usr/bin/env bash
die() {
printf '%s\n' "$1" >&2
exit 1
}
printparse(){
if [ ${VERBOSE} -gt 0 ]; then
printf 'Parse: %s%s%s\n' "$1" "$2" "$3" >&2;
fi
}
showme(){
if [ ${VERBOSE} -gt 0 ]; then
printf 'VERBOSE: %s\n' "$1" >&2;
fi
}
VERBOSE=0
## index for imported values in optary and valary arrays
idx=0
## Need v first so VERBOSE is set early
optspec=":vh-:"
while getopts "$optspec" OPTCHAR; do
case "${OPTCHAR}" in
-)
showme "OPTARG: ${OPTARG[*]}"
showme "OPTIND: ${OPTIND[*]}"
showme "OPTCHAR: ${OPTCHAR}"
showme "There is no equal sign in ${OPTARG}"
opt=${OPTARG}
val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
printparse "--${OPTARG}" " " "\"${val}\""
if [[ "$val" == -* ]]; then
die "ERROR: $opt value must be supplied"
fi
optary[${idx}]=${opt}
valary[${idx}]=${val}
idx=$(($idx + 1))
;;
h)
echo "usage: $0 [-v] [--anyOptYouQant[=]<valueIsRequired>] [--another[=]<value>]" >&2
exit 2
;;
v)
## if -v flag is present, it means TRUE
VERBOSE=1
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
die "Undefined argument: '-${OPTARG}'"
fi
;;
esac
done
echo "After Parsing values, ordinary getopts"
echo "VERBOSE $VERBOSE"
echo 'Arrays of opts and values'
echo "optary: ${optary[*]}"
echo "valary: ${valary[*]}"
【问题讨论】:
-
因为它是一个整数,它会将您引导到位置参数之一,$1, $2, ...
-
使用 getopts 解析长选项似乎是一种非常不正当的黑客行为。我会改用
getopt(example usage) -
getopt(来自 util-linux)在某些平台上不可用,所以我们选择不依赖它。