Created
May 3, 2019 13:46
-
-
Save hlfbt/2144c186b9d374dab4135600dda7a37c to your computer and use it in GitHub Desktop.
Simple somewhat advanced getopts only dependent on bash and expr
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
#!/bin/bash | |
# Simple more advanced arguments parsing than builtin tools like getopts or a simple while/case looping over the arguments | |
# | |
# Features include handling of: | |
# - multiple grouped shorthands (f.i. -abc becoming -a -b -c), | |
# - equal sign value assignment (f.i. --arg=value becoming --arg value, and also -a=value becoming -a value) | |
# - dashless value assignment (f.i. arg=value becoming arg value) | |
# | |
# The only dependencies are bash (for arrays) and expr (included in coreutils) (for regexp matching and extraction) which are likely available everywhere (even in a busybox or on a mac!) | |
# | |
# Author: Alexander Schulz ([email protected]) | |
# | |
parse_args() { | |
local key val | |
while [ $# -gt 0 ]; do | |
# Transform `-abc` into `-a -b -c`, with special handling of keeping passed values for the last arg (i.e. `-abc=value` becomes `-a -b -c=value`) | |
if expr "$1" : '-[^-].\+' >/dev/null; then | |
val="$1" | |
key=() | |
while [ "${#val}" -gt 1 ]; do | |
# Special case where the argument has a value (f.i. `-a=value`) | |
if expr "$val" : '-[^=]=.*' >/dev/null; then | |
key=( "${key[@]}" "$val" ) | |
val="-" | |
else | |
key=( "${key[@]}" "$(expr "$val" : '\(-.\).*')" ) | |
val="-$(expr "$val" : '-.\(.*\)')" | |
fi | |
done | |
set -- "${key[@]}" "${@:2}" | |
fi | |
# Transform `--arg=value` into `--arg value`, where both leading dashes are optional (so `-a=...` and `arg=...` also work) | |
if expr "$1" : '-\?-\?[^=]\+=.\+' >/dev/null; then | |
key="$(expr "$1" : '\(-\?-\?[^=]\+\)=.\+')" | |
val="$(expr "$1" : '-\?-\?[^=]\+=\(.\+\)')" | |
set -- "$key" "$val" "${@:2}" | |
fi | |
# The actual arguments handling happens here | |
case "$1" in | |
-s|--silent|silent) | |
SILENT=1 | |
;; | |
-u|--user|user) | |
USER="$2" | |
shift # We have to shift the positional arguments when we consume the second one as well! | |
;; | |
-l|--log-file|log[-_]file) | |
LOG_FILE="$2" | |
shift | |
;; | |
-h|--help|help) | |
print_help | |
;; | |
esac | |
shift | |
done | |
} | |
# Example of valid usage: | |
# (setting the silent flag, printing the help, setting the user to foobar and setting the log file to script.log) | |
parse_args --silent -hu=foobar log_file=script.log | |
# Inside a script, you'll probably want to adapt the case block and then simply call the parse_args (or otherwise renamed) function before the main execution like so: | |
parse_args "$@" | |
# This has the cool side effect, that the actual positional arguments won't be modified, and you can also pass any arbitray arguments | |
# So you could for example also pass all but the first positional arguments like so: | |
parse_args "${@:2}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment