Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Option parser in bash more evolved than getopts

I manipulate dozens of bash scripts in which I'm likely to change options. Changing the options involves three operations :

  • Changing the string you provide to getopts to parse options (:g:h:pt for example)
  • Write the piece of code to affect arguments (opt1=$OPTARG)
  • Changing the usage function (the function which displays a description of the description)

This is a bit heavy, especially when you know that boost::program_options provide a nice interface to handle options in C++.

Is there something similar to boost::program_options in Bash ?

like image 468
Guillaume Thomas Avatar asked Aug 01 '11 09:08

Guillaume Thomas


2 Answers

Use argbash. You won't regret it.

Argbash documentation

Argbash uses getopts in the background, but manages most of the implementation for you and provides a more consistent parsing codebase across projects. I've used it successfully, and its awesome, but does have a learning curve. Its a code generator that creates a parser script that supports long and short options, and creates help documentation automatically. It will even help with man pages.

The basic steps are:

  1. Install argbash. You can use the install instructions on site to compile, but I recommend using Docker container

  2. create a template m4 file, defining your options. You can do this manually or create a script.

    If you are using the docker container, it would be something like:

    argbash-init-docker \
    --opt myoption1 \
    --opt-bool myoption2 \
    --pos my_arg1 \
    --pos my_arg2 \
    parser.m4
    
  3. Run argbash with the template you generated as an input.

    Something like:

    argbash-docker \
    parser.m4 \
    --strip user-content \
    -o parser.sh
    
  4. In your main script that will be using the parser, source the parser.sh script from the output of the previous command

    source ./parser.sh

  5. Reference the options in your code

    An example of how you'd reference a boolean option:

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

    ./my-script.sh --myoption2 arg1 arg2
    
  7. repeat

As for your concern of manual steps, argbash allows you to keep it to a minimum. You can get it to a point that you are just updating the template and running a build script.My current implementation does have more manual steps than I'd like, but I'll be automating them out soon.

I have a more detailed outline of how I use it in my project here README-Argbash, and you can look at my code to see how I use it in the main script.

Option 2 - Use docopts , the docopt implementation for Bash.

The downside of the docopts is that it requires the docopt interpreter to be separately distributed to each user of your cli. This is a no-go for me. As a side note, Argbash can generate a docopt compliant help documentation to be used as the docopt template.

like image 86
AndrewD Avatar answered Sep 23 '22 16:09

AndrewD


Use getoptions.

https://github.com/ko1nksm/getoptions

getoptions is a new option parser (generator) written in POSIX-compliant shell scripts for those who want to support POSIX and GNU standard option syntax in your shell scripts (dash, bash, ksh, zsh and all POSIX shells).

It is fast and small, while supporting abbreviated long options, subcommands, automatic help generation, etc. And it is very easy to use because it is implemented with pure shell functions and does not require any other tools.

It is also an option parser generator. Pre-generating the option parser code eliminates the need for including the libraries and makes it even faster.

Example (this is all):

#!/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
like image 28
Koichi Nakashima Avatar answered Sep 22 '22 16:09

Koichi Nakashima