Skip to content

Instantly share code, notes, and snippets.

@ambakshi
Last active Jan 10, 2021
Embed
What would you like to do?
parse-opts.sh
#!/usr/bin/env bash
#
# MIT Licensensed
# Amit Bakshi Jan 2021
# Generic option parser.
# Usage:
# parse_opts --valid-args 'foo bar link' -- --with-foo=yes --bar=fizz --no-link
#
# Yields:
# O_foo=true
# O_bar=fizz
# O_link=false
#
# TODO: Add help generation, maybe from a heredoc that can also serve to
# provide the valid options.
#
parse_opts() {
local valid_args="debug verbose quiet"
while [ $# -gt 0 ]; do
local cmd="$1"
shift
case "$cmd" in
--) break;;
--valid-args=*) valid_args+=' '"${cmd#--valid-args=}";;
--valid-args) valid_args+=" $1"; shift;;
*) echo >&2 "Invalid option for this section"; return 144;;
esac
done
while [ $# -gt 0 ]; do
local cmd key value prefix
cmd="${1#--}"
if [ -n "$cmd" ] && [[ "$cmd" =~ ^([a-zA-Z][a-zA-Z0-9_-]*) ]]; then
cmd="${cmd#--}"
if [[ "$cmd" =~ ^(without|disable|enable|with) ]]; then
prefix=${BASH_REMATCH[1]}
cmd="${cmd#$prefix}"
cmd="${cmd#-}"
fi
key="${cmd%%=*}"
value="${cmd#$key=}"
sep="${cmd%$value}"
sep="${sep#$key}"
if [ -z "$sep" ]; then
value=true
elif [ "$sep" = '=' ]; then
value="${cmd#$key=}"
else
echo >&2 "ERROR: Invalid argument. Should be --foo=bar: $1"
return 1
fi
if [[ "$prefix" =~ ^(without|disable)$ ]]; then
if [[ "$value" =~ ^(false|disabled|no|0)$ ]]; then
value=true
elif [[ "$value" =~ ^(true|enabled|on|1)$ ]]; then
value=false
fi
elif [[ "$prefix" =~ ^(with|enable)$ ]]; then
if [[ "$value" =~ ^(false|disabled|no|0)$ ]]; then
value=false
elif [[ "$value" =~ ^(true|enabled|on|1)$ ]]; then
value=true
fi
elif [ -z "$prefix" ]; then
value="${value:-true}"
else
echo >&2 "ERROR: Invalid option $1"
return 1
fi
key="${key//-/_}"
if [[ "$valid_args" =~ $key ]]; then
eval "O_${key}=$value"
else
echo >&2 "Invalid option: $key"
return 145
fi
else
shift
echo "$@"
return $#
fi
shift
done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment