Command line argument validation library for Bash
bash, shell
Solution
This is the solution I use (found it on the net somewhere, probably here itself, don't remember for sure). Please note that the GNU getopt (`/usr/bin/getopt`) does support single dash long options (`ant -projecthelp` style) using the option `-a`, however I haven't used it so it is not shown in the example.
This code parses for 3 options: `--host value` or `-h value`, `--port value` or `-p value` and `--table value` or `-t value`. In case the required parameter isn't set, a test for it is
# Get and parse options using /usr/bin/getopt
OPTIONS=$(getopt -o h:p:t: --long host:,port:,table: -n "$0" -- "$@")
# Note the quotes around `$OPTIONS': they are essential for handling spaces in
# option values!
eval set -- "$OPTIONS"
while true ; do
case "$1" in
-h|--host) HOST=$2 ; shift 2 ;;
-t|--table)TABLE=$2 ; shift 2 ;;
-p|--port)
case "$2" in
"") PORT=1313; shift 2 ;;
*) PORT=$2; shift 2 ;;
esac;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
if [[ -z "$HOST" ]] || [[-z "$TABLE" ]] || [[ -z "$PORT" ]] ; then
usage()
exit
if
An alternative implementation using the `getopts` shell builtin(this only supports small options):
while getopts ":h:p:t:" option; do
case "$option" in
h) HOST=$OPTARG ;;
p) PORT=$OPTARG ;;
t) TABLE=$OPTARG ;;
*) usage(); exit 1 ;;
esac
done
if [[ -z "$HOST" ]] || [[-z "$TABLE" ]] || [[ -z "$PORT" ]] ; then
usage()
exit
if
shift $((OPTIND - 1))
Further reading for GNU getopt and getopts bash builtin
Problem
I am looking for a reusable code snippet that does command line argument validation for bash. Ideally something akin to the functionality offered by Apache Commons CLI: Commons CLI supports different types of options: - POSIX like options (ie. tar -zxvf foo.tar.gz) - GNU like long options (ie. du --human-readable --max-depth=1) - Short options with value attached (ie. gcc -O2 foo.c) - long options with single hyphen (ie. ant -projecthelp) - ... and it generates a "usage" message for the program automatically, like this: ``` usage: ls -A,--almost-all do not list implied . and .. -a,--all do not hide entries starting with . -B,--ignore-backups do not list implied entried ending with ~ -b,--escape print octal escapes for nongraphic characters --block-size <SIZE> use SIZE-byte blocks -c with -lt: sort by, and show, ctime (time of last modification of file status information) with -l:show ctime and sort by name otherwise: sort by ctime -C list entries by columns ``` I would include this code snippet at the beginning of my Bash scripts and reuse it across scripts. There must be something like this. I don't believe we are all writing code to this effect or similar: ``` #!/bin/bash NUMBER_OF_REQUIRED_COMMAND_LINE_ARGUMENTS=3 number_of_supplied_command_line_arguments=$# function show_command_usage() { echo usage: (...) } if (( number_of_supplied_command_line_arguments < NUMBER_OF_REQUIRED_COMMAND_LINE_ARGUMENTS )); then show_command_usage exit fi ... ```