bash 案例 && 额外的 OPTARG

bash 案例 && 额外的 OPTARG

昨晚我遇到了一个有趣的场景,到目前为止,我的 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-rgetopt

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

注意,当你用谷歌搜索getoptsvs.时getopt,你会发现很多人在抱怨getopt。据我所知,这始终是关于旧版本的getopt,它确实有很多错误。我的经验是,它getopt有更多选择,也比getopts.

要检查您是否有增强getopt版本,您可以运行

getopt -T
echo $?

如果输出为4,则您拥有增强版本。

相关内容