Created
December 17, 2020 19:39
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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