From 35ee77fc9b63e5c7f33c3b718a3489b06650d5c2 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Sun, 28 Mar 2021 11:11:59 +0900 Subject: [PATCH] include/opt: Add parser for command line parameters Parsing of command line parameters and printing the help text adds a significant amount of boilerplate code to any shell script (when done thoroughly). This commit adds the opt module, which will parse short and long parameters, execute callbacks, and print the help text if either "-h" or "--help" were passed. --- include/opt.sh | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 include/opt.sh diff --git a/include/opt.sh b/include/opt.sh new file mode 100644 index 0000000..3c3c9a3 --- /dev/null +++ b/include/opt.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +__init() { + if ! include "log" "array"; then + return 1 + fi + + declare -Axg __opt_short=() + declare -Axg __opt_long=() + declare -Axg __opt_desc=() + declare -Axg __opt_flags=() + declare -Axg __opt_value=() + declare -Axg __opt_action=() + declare -Axg __opt_map=() + declare -xgi __opt_num=0 + declare -xgi __opt_longest=0 + + opt_add_arg "h" "help" "no" 0 \ + "Print this text" \ + opt_print_help + + return 0 +} + +opt_add_arg() { + local short + local long + local flags + local default + local desc + local action + + local optlen + + short="$1" + long="$2" + flags="$3" + default="$4" + desc="$5" + action="$6" + + if array_contains "$short" "${__opt_short[@]}" || + array_contains "$long" "${__opt_long[@]}"; then + return 1 + fi + + optlen="${#long}" + + __opt_short["$long"]="$short" + __opt_long["$short"]="$long" + __opt_flags["$long"]="$flags" + __opt_desc["$long"]="$desc" + __opt_value["$long"]="$default" + __opt_action["$long"]="$action" + + __opt_map["-$short"]="$long" + __opt_map["--$long"]="$long" + + if (( __opt_longest < optlen )); then + __opt_longest=optlen; + fi + + ((__opt_num++)) + + return 0 +} + +opt_print_help() { + local short + local shortopts + + shortopts="" + + for short in $(array_sort "${__opt_short[@]}"); do + shortopts+="$short" + done + + echo "Usage: $BASH_ARGV0 [-$shortopts]" + echo "" + echo "Options" + + for short in $(array_sort "${__opt_short[@]}"); do + local long + local desc + local optlen + local padding + + long="${__opt_long[$short]}" + desc="${__opt_desc[$long]}" + optlen="${#long}" + padding=$((__opt_longest - optlen)) + + printf " -%s --%s %*s %s\n" \ + "$short" "$long" "$padding" "" "$desc" + done + + return 2 +} + +opt_parse() { + local opt + local i + + for (( i = 1; i <= $#; i++ )); do + local param + local long + local flags + local value + local action + + param="${!i}" + long="${__opt_map[$param]}" + + if [[ -z "$long" ]]; then + log_error "Unrecognized parameter: $param" + return 1 + fi + + flags="${__opt_flags[$long]}" + action="${__opt_action[$long]}" + + if [[ "$flags" == "yes" ]]; then + ((i++)) + + if (( i > $# )); then + log_error "Missing argument after $param" + return 1 + fi + + value="${!i}" + else + value="${__opt_value[$long]}" + ((value++)) + fi + + __opt_value["$long"]="$value" + + if ! [[ -z "$action" ]]; then + local err + + "$action" "$long" "$value" + err="$?" + + if (( err != 0 )); then + return "$err" + fi + fi + done + + return 0 +} + +opt_get() { + local long + + long="$1" + + if ! array_contains "$long" "${!__opt_value[@]}"; then + return 1 + fi + + echo "${__opt_value[$long]}" + return 0 +} -- 2.47.3