Contents of test_docopts.sh
#!/usr/bin/env bash
# Usage:
# test_docopts.sh [--verbose] [--exit] --age=AGE --name=NAME --role=ROLE [--] <source> <destination>
# test_docopts.sh --help
# test_docopts.sh --usage
# test_docopts.sh --version
#
# Mandatory arguments to long options are mandatory for short options too.
#
# Positional arguments:
# <source> the template HTML file to fill in
# <destination> the output HTML file
#
# Mandatory options:
# -a AGE, --age=AGE the current age of the homepage's owner
# -n NAME, --name=NAME the name of the homepage's owner
# -r ROLE, --role=ROLE the role of the homepage's owner (u: user, m:
# moderator, b: bot)
#
# Optional options:
# -e, --exit exit directly after parsing, for runtime assessment
# -v, --verbose output verbose information
#
# Help options:
# -h, -?, --help display this help and exit
# -u, --usage display the usage and exit
# -V, --version display the version and exit
function usage() {
# Define the usage message.
local usage
usage="Usage: $0 [-h,-? | -u | -V] [-e] [-v] -a=AGE -n=NAME -r={u,m,b} "
usage+="source destination"
printf '%s\n' "${usage}"
}
# Parse the arguments.
source docopts.sh --auto "$@"
# Check for the usage and version options. The help option is handled
# by docopts.sh.
if [[ "${ARGS[--usage]}" == true ]]; then
usage
exit
elif [[ "${ARGS[--version]}" == true ]]; then
printf '%s v1.0.0\n' "$0"
exit
fi
# Check the arguments' values.
name="${ARGS[--name]}"
age="${ARGS[--age]}"
if [[ "${age}" != ?([+-])+([[:digit:]]) ]]; then
printf '%s: Error: The option -a,--age must be an integer.\n' "$0"
usage >&2
exit 1
fi
role="${ARGS[--role]}"
if [[ "${role}" != [[:print:]] ]]; then
printf '%s: Error: The option -r,--role must be a single character.\n' "$0"
usage >&2
exit 1
fi
case "${role}" in
"u") role="User" ;;
"m") role="Moderator" ;;
"b") role="Bot" ;;
*)
printf '%s: Error: The option -r,--role must be in {u, m, b}.\n' "$0"
usage >&2
exit 1
;;
esac
verbose="${ARGS[--verbose]}"
# Set the positional arguments to variables.
in_file="${ARGS[<source>]}"
out_file="${ARGS[<destination>]}"
# Possibly, exit prematurely.
[[ "${ARGS[--exit]}" == true ]] && exit
# Run the HTML processor.
if [[ "$0" == */* ]]; then
cd "${0%/*.sh}" || exit 1
fi
source process_html_template.shExample calls:
# Long options.
bash test_docopts.sh --verbose --name="A. R. G. Parser" --age=2 --role=b template.html argparser.html
# Short options.
bash test_docopts.sh -v -a 2 -n "A. R. G. Parser" -r b template.html argparser.html
# Merged short options.
bash test_docopts.sh -va 2 -n "A. R. G. Parser" -r b template.html argparser.html
# Leading positional arguments.
bash test_docopts.sh template.html argparser.html --verbose --name="A. R. G. Parser" --age=2 --role=b
# Positional arguments delimiter "--".
bash test_docopts.sh --verbose --name="A. R. G. Parser" --age=2 --role=b -- template.html argparser.html
# Intermixed positional arguments.
bash test_docopts.sh --verbose --name="A. R. G. Parser" template.html --age=2 argparser.html --role=b
# Help, usage, and version messages.
bash test_docopts.sh --help
bash test_docopts.sh --usage
bash test_docopts.sh --versionNotes:
- Instead of defining the arguments and letting the parser create the help message, in docopts, the help message must be manually provided and the arguments definition gets extracted from there.
- Due to the rather complicated grammar, the usage string is likely incorrect, as the arguments to short options are interpreted as positional arguments. This requires some boilerplate code to get the actual values. Moreover, when using short options, they must be given in the order defined in the usage string as their values are normal positional arguments and as such parsed from left to right, irrespective of the preceding short option "flag" (as the parser interprets the definition). Thus, in the example calls, the long options are used, when necessary.
- The question mark
?for the help message is not supported, but emulated as--helpby a separate call.