Skip to content

Instantly share code, notes, and snippets.

@jefferys
Created December 17, 2020 19:39
Show Gist options
  • Save jefferys/61cc57abe25dee79f3f6aca340ba9003 to your computer and use it in GitHub Desktop.
Save jefferys/61cc57abe25dee79f3f6aca340ba9003 to your computer and use it in GitHub Desktop.
Bash option parsing example without using getopt and using globals instead of a hash
# Avoids string-keyed arrays as not available in old bash on Macs. Supports:
# * arguments and values with spaces if quoted.
# * arguments embedded in options (e.g. "commands").
# * arguments that look like option (start with a -) after a lone "--"
# * options with values, without values, and with optional values.
# * repeated options with values and counted flags.
# * both "key=value"" and "key value" style options
function parseCli() {
# globals
OPT_DOWNLOAD=0
OPT_MD5=0
OPT_INSTALL=0
OPT_REPORT=0
OPT_REPORT_FILE="packages.txt"
OPT_CACHE_DIR="" # Flag value for do not cache is ""
OPT_VERBOSE=0 # Counted flag
OPT_FORCE=0 # Counted flag
OPT_MANIFEST=()
OPT_ARGS=()
# Parameter list must be manually reduced on each loop using shift.
while [[ $# -gt 0 ]]; do
case "$1" in
# Flag
-d|--download)
OPT_DOWNLOAD=1
shift
;;
# Flag
-c|--checksum|--md5)
OPT_MD5=1
shift
;;
# Flag
-i|--install)
OPT_INSTALL=1
shift
;;
# Requires value if set
--cacheDir|--cacheDir=*)
if [[ $1 == *'='* ]]; then
OPT_CACHE_DIR="${1#*=}"
shift
elif [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
OPT_CACHE_DIR="$2"
shift 2
else
echo "Error: no directory specified for option --cacheDir." >&2
exit 1
fi
;;
# Optional value (tracks if set, even to default)
-r|--report|-r=*|--report=*)
if [[ $1 == *'='* ]]; then
OPT_REPORT=1
# Don't change if --option= without value.
[[ -n "${1#*=}" ]] && OPT_REPORT_FILE="${1#*=}"
shift
elif [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
OPT_REPORT=1
OPT_REPORT_FILE="$2"
shift 2
else
OPT_REPORT=1
shift
fi
;;
# Repeated value
-m|--manifest|-m=*|-manifest=*)
if [[ $1 == *'='* ]]; then
# Don't change if --option= without value.
[[ -n "${1#*=}" ]] && OPT_MANIFEST+=("${1#*=}")
shift
elif [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
OPT_MANIFEST+=("$2")
shift 2
else
echo "Error: no file specified for option -m | --manifest." >&2
exit 1
fi
;;
# Counted flag
-v|--verbose)
(( OPT_VERBOSE+=1 ))
shift
;;
# Counted flag
-q|--quiet)
(( OPT_VERBOSE-=1 ))
shift
;;
# Counted flag
-f|--force)
(( OPT_FORCE+=1 ))
shift
;;
# Terminate parsing to allow arguments that look like options
--)
shift
OPT_ARGS+=("$@")
break
;;
# Anything begining with - not already parsed is an error
-*)
echo "Error: Unknown option \"$1\"" >&2
exit 1
;;
# If not begining with "-", it is an option
*)
OPT_ARGS+=("$1")
shift
;;
esac
done
# Report option settings
if [[ $OPT_VERBOSE -gt 1 ]]; then
printf "Cli Parsing:\n"
printf " OPT_DOWNLOAD=%s\n" "$OPT_DOWNLOAD"
printf " OPT_MD5=%s\n" "$OPT_MD5"
printf " OPT_INSTALL=%s\n" "$OPT_INSTALL"
printf " OPT_REPORT=%s\n" "$OPT_REPORT"
printf " OPT_REPORT_FILE=%s\n" "$OPT_REPORT_FILE"
printf " OPT_VERBOSE=%s\n" "$OPT_VERBOSE"
printf " OPT_MANIFEST=%s\n" "${OPT_MANIFEST[@]}"
printf " OPT_ARGS=%s\n" "${OPT_ARGS[@]}"
printf " OPT_CACHE_DIR=%s\n" "$OPT_CACHE_DIR"
printf " OPT_FORCE=%s\n" "$OPT_FORCE"
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment