getopts可以解析bash脚本参数的一个子集,其余部分保持不变吗?

时间:2016-10-17 14:01:44

标签: bash getopts

我使用getopts来解析bash脚本中的参数。我想做两件事:

  • "$@"
  • 中删除已处理的选项
  • "$@"
  • 中保留未处理的选项

考虑命令行

$ foo -a val_a -b val_b -c -d -e -f val_f positional_l positional_2 ...

其中foo使用getopts来解析'b:c' optstring 定义的选项,之后需要将"$@"保留为

`-a val_a -d -e -f val_f positional_l positional_2 ...`

我需要做两件事:

  • 解析可能给出的选项子集
  • 保持所有其他选项不变

原因是foo必须使用它识别的选项来确定其必须传递剩余bar的另一个脚本"@"

通常getopts在遇到无法识别的选项时停止,但我需要它继续(直到任何--)。我需要它来执行并删除它识别的选项,并留下它没有的选项。

我确实尝试在--选项和foo选项之间使用bar解决我的问题,但如果getopts之后的文字--似乎无法解决问题}以-开头(我试过但无法逃脱连字符)。

无论如何我不想使用--,因为我希望bar的存在对foo的调用者有效透明,我希望调用者是foo能够以任何顺序显示选项。

我还尝试列出bar中的所有foo选项(即使用'a:b:cdef:'作为 optstring )而不处理它们但我需要删除已处理的选项来自"$@"。我无法弄清楚如何做到这一点(shift不允许指定位置。)

我可以手动重建一个新的选项列表(参见我自己的答案),但我想知道是否有更好的方法来做到这一点。

2 个答案:

答案 0 :(得分:3)

您可以手动重建选项列表,例如此示例处理-b-c选项并传递任何未完整的内容。

#!/bin/bash
while getopts ":a:b:cdef:" opt
do
  case "${opt}" in
    b) file="$OPTARG" ;;
    c) ;;
    *) opts+=("-${opt}"); [[ -n "$OPTARG" ]] && opts+=("$OPTARG") ;;
  esac
done
shift "$((OPTIND-1))"
./$file "${opts[@]}" "$@"

所以

./foo -a 'foo bar' -b bar -c -d -e -f baz one two 'three and four' five

将调用bar作为选项b的参数,作为

./bar -a 'foo bar' -d -e -f baz one two 'three and four' five

此解决方案的缺点是 optstring 必须包含传递选项(即":a:b:cdef:"而不是优先":b:c")。

用重建的参数列表替换参数列表可以这样做:

set -- "${opts[@]}" "$@"

将使"$@"包含问题中指定的未处理参数。

答案 1 :(得分:2)

请尝试以下操作,只需要提前知道脚本拥有选项

#!/usr/bin/env bash

passThru=() # init. pass-through array
while getopts ':cb:' opt; do # look only for *own* options
  case "$opt" in
    b)
      file="$OPTARG";;
    c) ;;
    *) # pass-thru option, possibly followed by an argument
      passThru+=( "-$OPTARG" ) # add to pass-through array
      # see if the next arg is an option, and, if not,
      # add it to the pass-through array and skip it
      if [[ ${@: OPTIND:1} != -* ]]; then
        passThru+=( "${@: OPTIND:1}" )
        (( ++OPTIND ))
      fi
      ;;
  esac
done
shift $((OPTIND - 1))
passThru+=( "$@" )  # append remaining args. (operands), if any

./"$file" "${passThru[@]}"

警告:有两种类型的歧义无法以这种方式解决

  • 对于带有选项参数的pass-thru选项,此方法仅在参数不是 直接附加到选项时才有效。 /> 例如,-a val_a有效,但-aval_a不会{在a:参数中没有getopts,这将被解释为选项并将其转换为多个选项-a-v-a-l-_-a)。

  • 正如chepner在对该问题的评论中指出的那样,-a -b可以是带有选项参数-a的选项-b(恰好看起来像一个选项本身),或者它可以是不同的选项-a-b;上述方法将采用后者。

要解决这些含糊之处,你必须坚持with your own approach,它必须提前知道所有可能的直通选项。