昨晚我遇到了一个有趣的场景,到目前为止,我的 google foo 一直无法找到解决方法。我有一个支持多个参数的脚本。用户(该死的那些用户)没有指定选项的参数,结果是......意想不到的。
代码:
while getopts "a:c:d:De:rs:" arg
do
case ${arg} in
a) app=${OPTARG} ;;
c) cmd=${OPTARG} ;;
d) domain=${OPTARG} ;;
D) Debug=1 ;;
e) env=${OPTARG} ;;
r) Doit=1 ;;
s) subapp=${OPTARG} ;;
*) echo "You are DISCREPANT!!";;
# *) usage "Invalid argument ${arg}::${OPTARG}" ;;
esac
done
if [ ${Debug} -gt 0 ]
then
echo "Env: ${env}"
echo "App: ${app}"
echo "Subapp: ${subapp}"
echo "Cmd: ${cmd}"
echo "Doit: ${Doit}"
echo "Debug: ${Debug}"
exit 1
fi
正确指定所有参数会导致:
$ ./mwctl -a weblogic -c start -s admin -e trn -r -D
Env: trn
App: weblogic
Subapp: admin
Cmd: start
Doit: 1
Debug: 1
忘记“-s”会导致:
$ ./mwctl -D -a weblogic -c start admin -e trn -r
Env:
App: weblogic
Subapp:
Cmd: start
Doit: 0
Debug: 1
使用选项跳过其他参数的结果类似。当遇到没有 OPT 的 OPTARG 时,“案例”似乎失去了理智......
我对如何抓住这个有点茫然。
答案1
传统的 Unix 约定是命令行有选项(包括选项的参数),然后命令的非选项参数。在 中mwctl -D -a weblogic -c start admin -e trn -r
,选项为-D
(无参数)、-a
(参数:weblogic
)和-c
(参数:start
)。下一个词是admin
,这不是一个选项,所以选项结束了。因此,非选项参数是admin
、-e
和。内置函数实现了这个约定。trn
-r
getopt
GNU 约定是一个以以下开头的参数-
命令行上的任何位置是一个选项,除非它前面有一个--
参数,但需要注意的是选项的参数不计算在内。根据 GNU 约定,在 中mwctl -D -a weblogic -c start admin -e trn -r
,有一个 option -D
、一个-a
带有参数的选项weblogic
、一个-c
带有参数的选项start
、一个非选项参数admin
、一个-e
带有参数的选项trn
和一个选项-r
。
case
不会“失去理智”,你的问题与 无关case
。您的代码缺少非选项参数的提取:
case $arg in …
esac
shift $((OPTIND - 1))
echo "There are $# non-option arguments, the first is $1"
如果该命令不支持任何非选项参数,则需要明确说明。
…
shift $((OPTIND - 1))
if [ $# -ne 0 ]; then
echo >&2 "Extraneous argument: $1"
exit 3
fi
答案2
我会使用getopt
而不是getopts
:
#!/usr/bin/env bash
OPT=$(getopt \
--options a:c:d:De:rs: \
--name "$0" \
-- "$@"
)
if [ $? -ne 0 ]; then
echo You are doing it wrong!
exit 1
fi
eval set -- "${OPT}"
while true; do
case "$1" in
-a) app=${2}; shift 2;;
-c) cmd=${2}; shift 2;;
-d) domain=${2}; shift 2;;
-D) Debug=1; shift;;
-e) env=${2}; shift 2;;
-r) Doit=1; shift;;
-s) subapp=${2}; shift 2;;
--) break;;
esac
done
echo "Env: ${env}"
echo "App: ${app}"
echo "Subapp: ${subapp}"
echo "Cmd: ${cmd}"
echo "Doit: ${Doit}"
echo "Debug: ${Debug}"
$ ./mwctl -a weblogic -c start -s admin -e trn -r -D
> Env: trn
> App: weblogic
> Subapp: admin
> Cmd: start
> Doit: 1
> Debug: 1
$ ./mwctl -D -a weblogic -c start admin -e trn -r
> Env: trn
> App: weblogic
> Subapp:
> Cmd: start
> Doit: 1
> Debug: 1
注意,当你用谷歌搜索getopts
vs.时getopt
,你会发现很多人在抱怨getopt
。据我所知,这始终是关于旧版本的getopt
,它确实有很多错误。我的经验是,它getopt
有更多选择,也比getopts
.
要检查您是否有增强getopt
版本,您可以运行
getopt -T
echo $?
如果输出为4
,则您拥有增强版本。