【问题标题】:How can I parse long-form arguments in shell?如何在 shell 中解析长格式参数?
【发布时间】:2012-03-05 11:54:11
【问题描述】:

我看到的所有内容都使用getopt 或稍微有点花哨的getopts,它只支持一个字符选项(例如,-h 但不支持--help)。我想做一些花哨的长选项。

【问题讨论】:

标签: bash shell sh


【解决方案1】:

我做过类似this:

_setArgs(){
  while [ "${1:-}" != "" ]; do
    case "$1" in
      "-c" | "--configFile")
        shift
        configFile=$1
        ;;
      "-f" | "--forceUpdate")
        forceUpdate=true
        ;;
      "-r" | "--forceRetry")
        forceRetry=true
        ;;
    esac
    shift
  done
}

如您所见,这很好地支持了单字符和更长的选项。它允许将值与每个参数相关联,例如--configFile。它的扩展性也很强,对于可以配置哪些选项等没有人为限制。

如上所述,"${1:-}" 可防止在 bash “严格”模式 (set -euo pipefail) 下运行时出现“未绑定变量”错误。

【讨论】:

  • 这可行,但不遵守某些约定:将单字母参数和-configFile=filename=)之类的东西折叠在一起。
  • @IanBicking - 非常正确。然而,就我的情况而言,我决定允许这一点,因为在 stackoverflow.com/questions/402377/… 的标记副本中提供的许多(尽管仍然很有价值)答案中回显了 getopt/getops 的挫败感。
  • 啊......当我写我的问题时,那个问题不在重复的候选中。谢谢!
  • 谢谢!调用函数:_setArgs $*
  • @Masa 不应该是_setArgs "$@" 吗?
【解决方案2】:

假设您“想做花哨的长选项”而不管工具如何,只需使用getoptgetopts 似乎主要在可移植性至关重要时使用)。这是一个example,您将获得最大的复杂性:

params="$(getopt -o e:hv -l exclude:,help,verbose --name "$(basename "$0")" -- "$@")"

if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$params"
unset params

while true
do
    case $1 in
        -e|--exclude)
            excludes+=("$2")
            shift 2
            ;;
        -h|--help)
            usage
            ;;
        -v|--verbose)
            verbose='--verbose'
            shift
            ;;
        --)
            shift
            break
            ;;
        *)
            usage
            ;;
    esac
done

使用此代码,您可以多次指定-e/--exclude,并且${excludes[@]} 将包含所有给定的排除项。处理后(-- 始终存在)剩余的任何内容都存储在 $@ 中。

【讨论】:

  • basename不将路径作为选项,而是作为参数。 (我无法编辑答案,因为系统需要至少 6 个字符编辑。)
  • 谢谢@jarno,不知道它是怎么溜进来的。
  • 另外,我认为你不需要使用${2-},但$2 就足够了,因为如果没有参数,getopt 将以非零代码退出对于-e,对吧?
【解决方案3】:

我创建了一个最容易使用且无需自定义的 bash 函数。只需使用该函数并传递所有带或不带参数的长选项,该函数会将它们设置为变量,并将相应的选项参数作为脚本中的值。

function get_longOpt {
  ## Pass all the script's long options to this function.
  ## It will parse all long options with its arguments,
  ## will convert the option name to a variable and
  ## convert its option value to the variable's value.
  ## If the option does not have an argument, the
  ## resulting variable's value will be set to true.
  ## Works properly when providing long options, only.
  ## Arguments to options may not start with two dashes.
  ##
  ####  Usage
  ##
  ## get_longOpt $@
  ##
  ##  May expand to:
  ##
  ## get_longOpt --myOption optimopti --longNumber 1000 --enableMe --hexNumber 0x16
  ##
  ### Results in the bash interpretation of:
  ## myOption=optimopti
  ## longNumber=1000
  ## enableMe=true
  ## hexNumber=0x16
  ##
  local -a opt_list=( $@ )
  local -A opt_map
  local -i index=0
  local next_item
  for item in ${opt_list[@]}; do
    # Convert arg list to map.
    let index++
    next_item="${opt_list[$index]}"
    if   [[ "${item}" == --* ]] \
      && [[ "${next_item}" != --* ]] \
      && [[ ! -z "${next_item}" ]]
    then
      item="$(printf '%s' "${item##*-}")"
      opt_map[${item}]="${next_item}"
    elif [[ "${item}" == --* ]] \
      && { [[ "${next_item}" == --* ]] \
      || [[ -z "${next_item}" ]]; }
    then
      item="$(printf '%s' "${item##*-}")"
      opt_map[${item}]=true
    fi
  done
  for item in ${!opt_map[@]}; do
    # Convert map keys to shell vars.
    value="${opt_map[$item]}"
    [[ ! -z "${value}" ]] && \
    printf -v "$item" '%s' "$value"
  done
}

最新的原始源代码可在此处获得:

https://github.com/theAkito/akito-libbash/blob/master/bishy.bash

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 2014-10-10
    • 2020-01-18
    相关资源
    最近更新 更多