Last active
June 17, 2019 11:40
-
-
Save dberstein/2795cde8eb8a99f1d1951f859ee343bd to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env sh | |
########################################## | |
# args - shell arguments parsing library # | |
########################################## | |
# Usage: | |
# - function "args_parse" with the parameters to parse, response will be a temp filename used to store the | |
# parsed data (see "Arguments parsing" and "Cleanup"). | |
# Example: ARGS=$(args_parse "$@") | |
# | |
# - function "args_flag" with arguments parsing filename and argument name (see "Arguments querying"). | |
# Example: FLAG_VALUE=$(args_flag "${ARGS}" "flag-name") | |
# | |
# Arguments parsing: | |
# | |
# Long flag arguments: | |
# "--<name>=[<value>]": continuos text between double dash and equal sign is flag name | |
# "--<name> <value>": same as above but value os obtainer from next argument | |
# | |
# Short flag arguments: | |
# "-<n><value>": single dash can have a single character name, its value can be adjacent to it | |
# (please note that "-n<n>=value" is parsed as "n" equals to "=value") ... | |
# "-<n> <value>": .. or can be the next argument | |
# | |
# Switch arguments (value-less): | |
# Some arguments usually not need a value (ie. -h or --help), this is supported using the env var | |
# "ARG_SWITCH_FLAGS", whose content must be a string listing the flags that should be trated as value-less | |
# switches. Short flag switches aer denoted by their single character name, long flag switches by a dash | |
# followed by their name. Example: export ARG_SWITCH_FLAGS="h -help" would allow both "-h" and "--help" to | |
# be value-less flags. An error is throw if a value is tried to be assigned. If flag is used it'll have the fixed | |
# value of "1". | |
# | |
# "-<n>" or "--<name>": If flag name is registered as "ARG_SWITCH_FLAGS" then its value will be set to "1" | |
# | |
# Positional arguments: | |
# All text starting from the first non-flag argument or the standard marker "--" are considered positional | |
# parameters whose value can be queried using key "--" | |
# | |
# "--": any argument following this is treated as a positional argument | |
# | |
# If an argument's prefix is of the form "--<name>", | |
# | |
# Argument querying: | |
# Call function args_flag with the arguments filename and the argument name (long flags must be prefixed by a dash). | |
# The response will be all arguments that match the given flag name. | |
# | |
# Positional arguments: | |
# Positional arguments can be obtained by querying argument name "--" | |
# | |
# Cleanup: | |
# In order to cleanup the temporary arguments file, its recommended to use a trap. For example: | |
# trap '[ -f "${ARGS}" ] && rm "${ARGS}"' INT TERM EXIT && \ | |
# ARGS=$(ARG_SWITCH_FLAGS="h -help" args_parse "$@") | |
# | |
args_echo_error () { | |
>&2 echo "$@" | |
} | |
arg_parse_is_switch () { | |
local SWITCH | |
if [ -n "$1" ]; then | |
SWITCH="$(echo "$3" | sed 's/-/\\-/')" && \ | |
echo "$1" | egrep -q '(^|\s)'${SWITCH}'(\s|$)' && \ | |
return $? | |
fi | |
return 1 | |
} | |
arg_parse_switch_invalid_error () { | |
[ -f "${FILE}" ] && rm "${FILE}" | |
args_echo_error "ERROR argument does not accept a value: -${1}" | |
return 2 | |
} | |
arg_parse_error_switch () { | |
echo "$1" | egrep -q '(^|\s)'$(echo "$2" | sed 's/-/\\-/')'(\s|$)' && \ | |
arg_parse_switch_invalid "${NAME}" && \ | |
return $? | |
return 0 | |
} | |
args_parse () { | |
local FILE; local NAME; local VALUE; local SWITCH_STATUS | |
FILE="$(mktemp)" | |
# while we have arguments ... | |
while [ $# -gt 0 ]; do | |
VALUE=""; SWITCH_STATUS=0 | |
ARG="$1" && shift | |
# stop parsing, treat remainder as positional arguments | |
if [ '--' = "${ARG}" ]; then | |
echo "--=${@}" >> "${FILE}"; break | |
# long argument: value attached to argument after "=" sign | |
elif echo "${ARG}" | egrep -q '^--[^=]+=.*$'; then | |
NAME=$(echo "${ARG}" | sed 's/^--\([^=]*\)=.*$/-\1/') | |
if arg_parse_is_switch "${ARG_SWITCH_FLAGS}" "${ARG}" "${NAME}"; then | |
arg_parse_switch_invalid_error "${NAME}" | |
return $? | |
fi | |
VALUE=$(echo "${ARG}" | sed 's/^--.*=\(.*\)$/\1/') | |
# long argument: next arg has value or is switch flag | |
elif echo "${ARG}" | egrep -q '^--[^=]+$'; then | |
NAME=$(echo "${ARG}" | sed 's/^--/-/') | |
# switch flag cannot have value | |
if arg_parse_is_switch "${ARG_SWITCH_FLAGS}" "${ARG}" "${NAME}"; then | |
VALUE="1" | |
else | |
[ $# -gt 0 ] && VALUE="$1" && shift | |
fi | |
# short argument: value attached to argument | |
elif echo "${ARG}" | egrep -q '^-[^-].'; then | |
NAME=$(echo "${ARG}" | sed 's/^-\([^-]\).*$/\1/') | |
if arg_parse_is_switch "${ARG_SWITCH_FLAGS}" "${ARG}" "${NAME}"; then | |
arg_parse_switch_invalid_error "${NAME}" | |
return $? | |
fi | |
VALUE=$(echo "${ARG}" | sed 's/^-[^-]\(.*\)/\1/') | |
# short argument: next arg has value or is switch flag | |
elif echo "${ARG}" | egrep -q '^-[^-]$'; then | |
NAME=$(echo "${ARG}" | sed 's/^-\([^-]\)$/\1/') | |
if arg_parse_is_switch "${ARG_SWITCH_FLAGS}" "${ARG}" "${NAME}"; then | |
VALUE="1" | |
else | |
[ $# -gt 0 ] && VALUE="$1" && shift | |
fi | |
# non-flag argument, stop parsing, treat remainder as positional arguments | |
else | |
echo "--=${ARG}" >> "${FILE}"; echo "--=${@}" >> "${FILE}"; break | |
fi | |
echo "${NAME}=${VALUE}" >> "${FILE}" | |
done && echo "${FILE}" | |
} | |
args_flag () { | |
# Returns flag arguments for flag $2. | |
# $1 (string) args filename. | |
# $2 (string) flag, long flags shou;d be prefixed by a dash. | |
grep "^$2=" "$1" | cut -d= -f2- | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment