Created
April 17, 2020 17:22
-
-
Save multun/e2ba07dbb6b4088ccf3494d804ef1b8c to your computer and use it in GitHub Desktop.
A shell library for parsing arguments
This file contains hidden or 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
# parse --my_option into the MY_OPTION variable | |
# also handles positional arguments | |
__args_list=() | |
__required_args_list=() | |
__unexport_args_list=() | |
normalize_argument() { | |
# uppercase | |
local argname="${1^^}" | |
# replace - by _ | |
printf '%s\n' "${argname}" | tr - _ | |
} | |
assign_var() { | |
# printf can assign variables | |
printf -v "$1" '%s' "$2" | |
} | |
# public arguments get forwarded through the environment | |
public_optional_argument() { | |
local argname="$(normalize_argument "$1")" | |
__args_list+=( "${argname}" ) | |
assign_var "__args_${argname}" 1 | |
} | |
public_required_argument() { | |
local argname="$(normalize_argument "$1")" | |
assign_var "__args_${argname}" 1 | |
__args_list+=( "${argname}" ) | |
__required_args_list+=( "${argname}" ) | |
} | |
optional_argument() { | |
local argname="$(normalize_argument "$1")" | |
assign_var "__args_${argname}" 1 | |
__args_list+=( "${argname}" ) | |
__unexport_args_list+=( "${argname}" ) | |
} | |
required_argument() { | |
local argname="$(normalize_argument "$1")" | |
assign_var "__args_${argname}" 1 | |
__args_list+=( "${argname}" ) | |
__required_args_list+=( "${argname}" ) | |
__unexport_args_list+=( "${argname}" ) | |
} | |
undefined_variable() { | |
[ "${!1+x}" == '' ] | |
} | |
__positional_arg_count=0 | |
positional_argument() { | |
assign_var "__positional_arg_$((__positional_arg_count++))" "$(normalize_argument "$1")" | |
} | |
__arguments_parsed=0 | |
log_command() { | |
if [ "${__arguments_parsed}" = 0 ]; then | |
error "call parse_arguments before log_command" | |
exit 1 | |
fi | |
local argname | |
# print the environment variables | |
for argname in "${__args_list[@]}"; do | |
if ! undefined_variable "$argname"; then | |
printf '%s=%q ' "$argname" "${!argname}" | |
fi | |
done | |
# print the script path | |
printf '%s' "$0" | |
# print the positional arguments | |
if [ "${#positional_arguments[@]}" != 0 ]; then | |
printf '%s' ' --' | |
printf ' %s' "${positional_arguments[@]}" | |
fi | |
printf '\n' | |
} | |
parse_arguments() { | |
__arguments_parsed=1 | |
while [ $# != 0 ]; do | |
local argument="$1" | |
if [ "$argument" = '--' ]; then | |
shift | |
positional_arguments=( "$@" ) | |
break | |
fi | |
case "$argument" in | |
--*) | |
local argname="$(normalize_argument "${argument#--}")" | |
local slotname="__args_${argname}" | |
if [ "${!slotname}" != '1' ]; then | |
error "unknown named argument: $argument ($argname)" | |
exit 1 | |
fi | |
if [ $# -lt 2 ]; then | |
error "missing value for parameter ${argname}" | |
exit 1 | |
fi | |
shift | |
assign_var "$argname" "$1" ;; | |
*) # when meeting a non option argument, stop parsing | |
positional_arguments=( "$@" ) | |
break ;; | |
esac | |
shift | |
done | |
# error out when there are too many positional arguments | |
local pos_arg_count="${#positional_arguments[@]}" | |
if [ "${pos_arg_count}" -gt "${__positional_arg_count}" ]; then | |
error "too many positional arguments" | |
exit 1 | |
fi | |
# error out when there are too few positional arguments | |
if [ "${pos_arg_count}" -lt "${__positional_arg_count}" ]; then | |
for ((i=pos_arg_count; i < __positional_arg_count; i++)); do | |
local arg_name_var="__positional_arg_$i" | |
error "missing positional argument: ${!arg_name_var}" | |
done | |
exit 1 | |
fi | |
# assign positional argument variables | |
for ((i=0; i < __positional_arg_count; i++)); do | |
local arg_name_var="__positional_arg_$i" | |
local arg_name="${!arg_name_var}" | |
assign_var "${arg_name}" "${positional_arguments[i]}" | |
done | |
# detect missing mandatory arguments | |
for arg in "${__required_args_list[@]}"; do | |
if undefined_variable "$arg"; then | |
error "missing required argument: $arg" | |
exit 1 | |
fi | |
done | |
# unexport arguments | |
for arg in "${__unexport_args_list[@]}"; do | |
export -n "$arg" | |
done | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment