【问题标题】:Option parser in bash more evolved than getoptsbash 中的选项解析器比 getopts 更进化
【发布时间】:2011-10-17 07:03:43
【问题描述】:

我操作了几十个 bash 脚本,我可能会在其中更改选项。更改选项涉及三个操作:

  • 更改您提供给 getopts 的字符串以解析选项(例如:g:h:pt
  • 编写一段代码来影响参数 (opt1=$OPTARG)
  • 更改使用功能(显示描述描述的功能)

这有点重,尤其是当您知道boost::program_options 提供了一个很好的接口来处理 C++ 中的选项时。

在 Bash 中是否有类似于 boost::program_options 的东西?

【问题讨论】:

标签: parsing bash options


【解决方案1】:

使用 argbash。你不会后悔的。

Argbash documentation

Argbash 使用getopts in the background,但会为您管理大部分实现,并提供跨项目的更一致的解析代码库。我用过它successfully,它很棒,但确实有一个学习曲线。它是一个代码生成器,可创建支持长选项和短选项的解析器脚本,并自动创建帮助文档。它甚至可以帮助处理手册页。

基本步骤是:

  1. 安装 argbash。可以使用现场的安装说明进行编译,但我推荐使用Docker container

  2. 创建一个模板 m4 文件,定义您的选项。您可以手动执行此操作或创建脚本。

    如果你使用的是 docker 容器,它会是这样的:

    argbash-init-docker \
    --opt myoption1 \
    --opt-bool myoption2 \
    --pos my_arg1 \
    --pos my_arg2 \
    parser.m4
    
  3. 使用您生成的模板作为输入运行 argbash。

    类似:

    argbash-docker \
    parser.m4 \
    --strip user-content \
    -o parser.sh
    
  4. 在将使用解析器的主脚本中,从上一个命令的输出中获取 parser.sh 脚本

    source ./parser.sh

  5. 引用代码中的选项

    如何引用布尔选项的示例:

     if test $_arg_myoption2 = on;then
     echo 'myoption2 is on'
     fi
    
  6. 测试

    ./my-script.sh --myoption2 arg1 arg2
    
  7. 重复

至于您对手动步骤的关注,argbash 允许您将其保持在最低限度。您可以理解为您只是在更新模板并运行构建脚本。我当前的实现确实有比我想要的更多的手动步骤,但我很快就会将它们自动化。

我在 README-Argbash 的项目中有更详细的使用它的概述,您可以查看我的 code 以了解我如何在主脚本中使用它。

选项 2 - 使用 docopts ,即 Bash 的 docopt 实现。

docopts 的缺点是它需要将 docopt 解释器单独分发给 cli 的每个用户。这对我来说是不行的。附带说明一下,Argbash 可以生成符合 docopt 的帮助文档,用作 docopt 模板。

【讨论】:

    【解决方案2】:

    使用 getoptions。

    https://github.com/ko1nksm/getoptions

    getoptions 是一个用 POSIX 兼容的 shell 脚本编写的新选项解析器(生成器),适用于那些希望在 shell 脚本(dash、bash、ksh、zsh 和所有 POSIX shell)中支持 POSIX 和 GNU 标准选项语法的人。

    速度快、体积小,同时支持简长选项子命令自动帮助生成等。而且非常容易使用,因为它是用纯 shell 函数实现的,不需要任何其他工具。

    它也是一个选项解析器生成器。预生成选项解析器代码消除了包含库的需要并使其更快。

    示例(仅此而已):

    #!/bin/sh
    
    VERSION=1.0
    
    parser_definition() {
      setup   REST help:usage abbr:true -- "Usage: example.sh [options] [arguments]" ''
      msg -- "Options:"
      flag    FLAG_A  -a
      flag    FLAG_B  -b
      flag    FLAG    -f +f --{no-}flag            -- "takes no arguments"
      param   PARAM   -p    --param                -- "takes one argument"
      option  OPTION  -o    --option on:"default"  -- "takes no arguments or one argument"
      disp    :usage  -h    --help
      disp    VERSION       --version
    }
    
    eval "$(getoptions parser_definition) exit 1"
    
    echo "FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION"
    printf ': %s\n' "$@" # Rest arguments
    
    script.sh -ab -f +f --flag --no-flag -p 1 -p2 --param 3 --param=4 --option=5 --op -- A B
    

    【讨论】: