💾 Archived View for gemini.kaction.cc › log › 2022-10-19.1.gmi captured on 2024-05-12 at 15:08:42. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-02-05)

-=-=-=-=-=-=-

Command line parsing for shell scripts

Recently I learned about docopt -- idea (anof generating command line parser from help message and implementation for multiple languages; conventional command line parsers do it other way round: help message from the parser. It was pleasant to discover something new in design area that seemed to be fully explored for decades.

https://docopt.org

Compared to powerful command line parsers found in high-level languages, like "click" for Python or "optparse-applicative" for Haskell, "docopt" is much less expressive and does not even distinguish between integer and string arguments. Comparing with other side of spectrum, "docopt" is as expressive as plain "getopt_long", but much nicer to write and maintain.

This is why learning about "docopts" (implementation of docopt standard for Bash) is valuable discovery for me. The only alternative for shell scripts is "getopt", which is awful. See example on wiki dedicated to best practices of GNU Bash programming.

http://mywiki.wooledge.org/BashFAQ/035

This is how it looks like in practice:

#!/usr/bin/env bash
#
# Usage: mod_sv NAME [--log-script=FILE|--no-log]
#                    [--finish-script=FILE]
#                    [--run-command=COMMAND]
#
# Runscript is read from stdin, unless --run-command is provided, in
# which case command provided will be executed using execlineb(1)
# interpreter.
#
# Options:
#   -h --help              display this help message
#   --no-log               do not generate standard svlogd(8)-based log script
#   --log-script=FILE      use custom log script
#   --finish-script=FILE   use custom finish script (not generated by default)
#   --run-command=COMMAND  simplified interface for defining runscript.

set -eu
source docopts.sh --auto "$@"

for a in ${!ARGS[@]} ; do
    echo "$a = ${ARGS[$a]}"
done

Of course, there is still room for improvement. For example, if user provides unknown option or both of mutually-exclusive options, full usage line is printed without clarification of what exactly was wrong.

Still, from help message that needs to be written anyway (since getopt does not generate it) decent command line parser is generated. Writing of the shell scripts is much easier now.