Bash getopts:识别否定选项(-x-或+ x)?

时间:2016-10-24 15:04:30

标签: bash shell command-line-arguments getopt getopts

(与this类似,但在bash中。)

我有一个现有的bash脚本,它使用内置的getopts来识别-s(仅标记 - 无参数)。我发现每次都使用该选项,所以我希望将其设为默认,除非在命令行中指定了 -s-+s。但是,虽然ksh getopts can handle +s,但我无法在bash getopts manual中找到该功能。

我目前的解决方法是:

  1. 使用s:,以便-s- = $OPTARG识别"-";或
  2. 使用其他选项替换-s,例如-d(“不要”)。
  3. 然而,#1有一个问题,如果我不小心指定了-s,它会吞下下一个参数,而#2的问题是它使用了与我肌肉记忆中已有的切换字母不同的切换字母。我希望可能有一种直接的方法来解析bash中的-s-+s

    • util-linux getopt(1)似乎也没有+s。它可以处理可选参数,因此可以使用-s-。但是,我之前没有使用过getopt(1),所以我会很感激如何不用脚射击自己。
    • BashFAQ 035说“自己解析”。如果您已经编写了+s-s-的例程,我很乐意看到它。

    我当前的arg-parsing循环非常基础:

    while getopts "nthps" opt ; do
        case "$opt" in
            <other cases cut>
            (s)     saw_s="yes"
                    ;;
        esac
    done
    shift $((OPTIND-1))
    

1 个答案:

答案 0 :(得分:2)

负标志(+abcdef +g)的序列与正常序列(-abcdef -g)的区别仅在于加号。因此,您只需恢复+前缀的标记值。

第二种形式的负序是如此简单。只需删除最后一个字符(-),并取消正常的标记值。

示例

以下脚本接受所有提到的格式,例如: -ns -n -s -n- -ns- +ns +n +s

arglist='ns'

while (( $# )); do
  arg="$1"

  # Parse -abcdef- (negative form of -abcdef) options
  if [ "${arg:0:1}" = '-' -a "${arg#${arg%?}}" = '-' ]; then
    flag_val=no
    arg="${arg%?}" # -abcdef- becomes -abcdef
  elif [ "${arg:0:1}" = '+' ]; then
    flag_val=no
    arg="${arg/#+/-}"
  else
    flag_val=yes
  fi

  # OPTIND is the index of the next argument to be processed.
  # We are going to parse "$arg" from the beginning, so we need
  # to reset it to 1 before calling getopts.
  OPTIND=1

  while getopts "$arglist" opt "$arg"; do
    case "$opt" in
      s) saw_s="$flag_val" ;;
      n) saw_n="$flag_val" ;;
    esac
  done

  shift
done

# Set default values
: ${saw_s:=yes}
: ${saw_n:=no}

printf "saw_s='%s'\nsaw_n='%s'\n" "$saw_s" "$saw_n"

测试

$ ./pargs.sh
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh +s
saw_s='no'
saw_n='no'
$ ./pargs.sh -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -s- +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s +s
saw_s='no'
saw_n='no'
$ ./pargs.sh +s -s
saw_s='yes'
saw_n='no'
$ ./pargs.sh -s -s-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn
saw_s='yes'
saw_n='yes'
$ ./pargs.sh -sn -s-
saw_s='no'
saw_n='yes'
$ ./pargs.sh -sn +s
saw_s='no'
saw_n='yes'
$ ./pargs.sh +sn
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn-
saw_s='no'
saw_n='no'
$ ./pargs.sh -sn- -n
saw_s='no'
saw_n='yes'