There is something to be said for the immediacy of using Bash scripts, especially when dealing with relatively simple system operations; however, parsing command line arguments has always been rather cumbersome and usually done along the lines of painful if [[ ${1} == '--build' ]]; then ....
On the other hand, Python is pretty convenient for system operations (especially when using the sh module) but sometimes a bit of an overkill, or just missing the immediacy of Bash: however, the argparse module is nothing short of awesome, when it comes to power and flexibility in parsing command line options.
This simple Python script tries to marry the best of both worlds, allowing with a relatively simple setup to parse arbitrary command line options, and then having their values reflected in the corresponding local environment variables.

Usage
The usage is rather straightforward: we invoke it with a list of the desired option names, followed by the actual command line arguments ($@) separated with --:
PARSED=$(parse-args keep- take counts! mount -- $@)
source ${PARSED}
the values of the arguments (if any) are then available via the ${ } operator:
if [[ -n ${keep} ]]; then
echo "Keeping mount: ${mount}"
fi
For example:
└─( ./test --keep --mount /var/loc/bac --take 3 --counts yes
Keeping mount: /var/loc/bac
Take: 3, counts: yes
Each argument can have a modifier: a trailing - (simple dash) for example indicates a “flag” (a boolean option, which takes no value and whose presence will result in the corresponding variable to be set), while a trailing ! indicates a required argument:
└─( ./test --keep --mount /var/loc/bac --take 3
usage: [-h] [--keep] [--take TAKE] --counts COUNTS [--mount MOUNT]
ERROR: the following arguments are required: --counts
The full description of all modifiers can be found here
Installation
Please see the full description of the common-utils package on GitHub, and how to install them to your machine.
Implementation
The source code is available here and revolves around adding arguments to argparse.ArgumentParser dynamically:
for arg in args:
required = False
if arg.endswith('!'):
required = True
arg = arg[:-1]
if arg.endswith('-'):
parser.add_argument(f"--{arg[:-1]}", required=required, action='store_true')
else:
parser.add_argument(f"--{arg}", required=required)
We have subclassed the ArgumentParser with a StderrParser so that:
- when erroring out, we emit error messages to
stderrso they don’t get “swallowed” in the bash script; and - we need to exit with an error code, so that using
set -ein our shell script will cause it to terminate, instead of executing thesourcecommand with potentially unexpected consequences.
class StderrParser(argparse.ArgumentParser):
def __init__(self, **kwargs):
super().__init__(prog='', **kwargs)
def exit(self, status=0, message=None):
if message:
print(message, file=sys.stderr)
exit(status)
def error(self, message):
self.print_usage(file=sys.stderr)
self.exit(status=1, message=f"ERROR: {message}")





Leave a reply to mattalxndr Cancel reply