【问题标题】:Bash getopts multiple flags with single required parameterBash getopts 具有单个必需参数的多个标志
【发布时间】:2016-05-23 17:02:41
【问题描述】:

我很难理解如何让 getopts 接受带有单个参数的多个标志。例如。

标志:孩子:a - 亚当 b - 贝丝 c - 凯茜 d - 邓肯

必填参数:冰淇淋口味

(不是我的脚本真正做的,但这样拼出来最容易)

我现在能做什么:

./flavor -a chocolate

./flavor -c chocolate 

我想做的事:

./flavor -acd chocolate

到目前为止,我能做到的不仅仅是它:

./flavor -a chocolate -c chocolate -d chocolate

我用 getopts 尝试的每个变体要么根本看不到参数,要么在每个标志声明之后都需要它。我觉得我错过了一些明显的东西,这会给我“啊哈”的时刻,但我自己并没有看到它。谁能指出我正确的方向?

=============================================

while getopts ":a:b:c:d:" opt; do
  case $opt in
        a)
          do stuff with $OPTARG
         ;;
        b) 
          do stuff with $OPTARG
         ;;
        c)
          do stuff with $OPTARG
         ;;
        d)
          do stuff with $OPTARG
         ;;
        :)
         echo "Option -$OPTARG requires an argument." >&2
         exit 1
         ;;
  esac
done

=============================================

如果这是一个非常愚蠢的问题,我深表歉意,并感谢您的宝贵时间。

【问题讨论】:

  • 你没有错过任何东西;没有办法指定单个参数应由组中的所有选项共享。
  • 我相信你做不到,但我可能错了。对于./flavor -acda 将消耗 cd 作为其$OPTARG

标签: bash getopts


【解决方案1】:
getopts 不支持需要参数的堆叠选项。您只能堆叠不带参数的选项。

要按照您的建议进行操作,需要在参数处理中增加很多复杂性。本质上,您必须对选项进行预处理以找出非选项参数的开始位置。这不是特别漂亮或推荐,但这确实可以满足您的要求,而无需其他选项:

_GETOPTS=":abcd"
while getopts "${_GETOPTS}" opt
do
  case $opt in
        abcd)
         :
         ;;
        \?)
         echo "Unsupported option (-${OPTARG})" >&2
         exit 1
         ;;
  esac
done
eval "FIRSTARG=\${${OPTIND}}"
if [ -z "${FIRSTARG}" ]
then
   echo "Flavor argument required."
   exit 1
fi
OPTIND=1
while getopts "${_GETOPTS}" opt
do
  case $opt in
        a)
         echo do a stuff with ${FIRSTARG}
         ;;
        b)
         echo do b stuff with ${FIRSTARG}
         ;;
        c)
         echo do c stuff with ${FIRSTARG}
         ;;
        d)
         echo do d stuff with ${FIRSTARG}
         ;;
  esac
done

结果:

$ ./flavor -acd chocolate
do a stuff with chocolate
do c stuff with chocolate
do d stuff with chocolate

可以在第一个非选项参数之后访问其他参数,但这需要更多的工作。

请注意,在多个 getopts 语句中处理同一组选项很容易产生长期维护问题,因为这两个 case 处理的选项可能太容易了em> 语句不同步。

【讨论】:

  • 谢谢。这让我走了大约 90% 的路。我现在只需要弄清楚如何使参数成为必需的,这样就不会被遗漏了。
  • 在第二个 while 语句之前插入类似于 if [ -z "${FIRSTARG}" ]; then echo Flavor argument required; exit 1; fi 的内容
  • 是的。奇迹般有效!再次感谢。 :)
【解决方案2】:

做这件事有点微妙的方式是:

 #!/bin/bash
while getopts ":abcdf:" opt; do
case $opt in
f)
FLAVOUR="$OPTARG"

if [ ${ADAM_IN:-0} -eq 1 ]
then
  echo "Adam gets $FLAVOUR"
  ADAM_IN=0
fi
if [ ${BETH_IN:-0} -eq 1 ]
then
  echo "Beth gets $FLAVOUR"
  BETH_IN=0
fi
if [ ${CATHY_IN:-0} -eq 1 ]
then
  echo "Cathy gets $FLAVOUR"
  CATHY_IN=0
fi
if [ ${DUNCAN_IN:-0} -eq 1 ]
then
  echo "Duncan gets $FLAVOUR"
  DUNCAN_IN=0
fi
;;
a)
  ADAM_IN=1
;;
b)
  BETH_IN=1
;;
c)
  CATHY_IN=1
;;
d)
  DUNCAN_IN=1
;;
:)
echo "invalid argument" 2>/dev/null
exit 1
;;
esac
done

将脚本另存为ice_cream_allocator 并运行如下:

$ ./ice_cream_allocator -abcf"Chocolate" -df"Vanila" -cf"Strawberry"

输出

Adam gets Chocolate
Beth gets Chocolate
Cathy gets Chocolate
Duncan gets Vanila
Cathy gets Strawberry

好吧,我为凯茜准备了一个软角,所以给了她两种口味;)

【讨论】:

  • 我知道你在这里做什么,但是当我去简化我的脚本实际上在做什么(即,不是冰淇淋)时,这将是不可行的。非常感谢您抽出宝贵时间回复并提供帮助。
  • @Mathaen:不客气,祝你好运。 :-)
猜你喜欢
  • 2014-05-23
  • 1970-01-01
  • 2014-03-30
  • 2013-04-17
  • 2012-07-02
  • 2014-03-09
  • 2011-11-23
  • 2020-10-23
相关资源
最近更新 更多