You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
6.5 KiB
185 lines
6.5 KiB
#!/bin/bash
|
|
|
|
# =============================================================================
|
|
# Bash CLI Argument Parser — Greedy Grouping, Flag-Agnostic
|
|
# =============================================================================
|
|
#
|
|
# Overview:
|
|
# Parses command-line arguments into key/value groups.
|
|
# Every flag (long or short) collects values until the next flag.
|
|
# You do NOT need to define which flags expect values.
|
|
# Short flags can be grouped (-abc) and are treated as booleans.
|
|
#
|
|
# Supported input formats:
|
|
# --key value1 value2 → key = [value1, value2]
|
|
# --key=value → key = value
|
|
# -k value → k = value
|
|
# -k=value → k = value
|
|
# -abc → a=true, b=true, c=true
|
|
#
|
|
# Not supported:
|
|
# -kvalue → this is parsed as combined short flags (k, v, a…)
|
|
# Global positionals not linked to any flag (can be added separately if needed)
|
|
#
|
|
# Example usage:
|
|
# ./arg_analyse.sh --mode fast --files input1.txt input2.txt -vx --output=result.txt
|
|
#
|
|
# Output:
|
|
# --mode:
|
|
# [0]: fast
|
|
# --files:
|
|
# [0]: input1.txt
|
|
# [1]: input2.txt
|
|
# --v:
|
|
# [boolean flag]
|
|
# --x:
|
|
# [boolean flag]
|
|
# --output:
|
|
# [0]: result.txt
|
|
#
|
|
# =============================================================================
|
|
|
|
# STORAGE: key = flag name, value = string or boolean
|
|
declare -A FLAG_GROUPS
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# FUNCTION: parse_grouped_args
|
|
# Description:
|
|
# Parses input arguments and fills the FLAG_GROUPS associative array.
|
|
# -----------------------------------------------------------------------------
|
|
parse_grouped_args() {
|
|
local current_flag=""
|
|
local -a current_values=()
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
local token="$1"
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Case 1: --key=value or -k=value (explicit assignment form)
|
|
# This handles both long and short flags passed as --flag=value or -f=value
|
|
# -------------------------------------------------------------------------
|
|
# Breakdown of regex:
|
|
# ^ → start of the string
|
|
# --? → match one or two dashes (e.g. "-" or "--")
|
|
# ([^=]+) → capture group 1: one or more characters that are NOT "="
|
|
# → this becomes the flag name (e.g. "output")
|
|
# = → literal equals sign
|
|
# (.*) → capture group 2: any number of characters (can be empty)
|
|
# → this becomes the first value for the flag
|
|
#
|
|
# Examples:
|
|
# --file=abc.txt → key = "file", val = "abc.txt"
|
|
# -x=1 → key = "x", val = "1"
|
|
if [[ "$token" =~ ^--?([^=]+)=(.*)$ ]]; then
|
|
# Before processing this --flag=value, we must flush any previous group
|
|
if [[ -n "$current_flag" ]]; then
|
|
if [[ ${#current_values[@]} -eq 0 ]]; then
|
|
FLAG_GROUPS["$current_flag"]="true"
|
|
else
|
|
FLAG_GROUPS["$current_flag"]="${current_values[*]}"
|
|
fi
|
|
fi
|
|
|
|
# Capture the key and value from the current --key=value or -k=value
|
|
local key="${BASH_REMATCH[1]}" # group 1 from regex (flag name)
|
|
local val="${BASH_REMATCH[2]}" # group 2 from regex (value after =)
|
|
|
|
# Set current flag context to continue collecting values if any follow
|
|
current_flag="$key"
|
|
current_values=("$val") # start a new value group with first value from assignment
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Case 2: --long flag (starts a new group)
|
|
# -------------------------------------------------------------------------
|
|
elif [[ "$token" == --* ]]; then
|
|
# Save previous flag (if any)
|
|
if [[ -n "$current_flag" ]]; then
|
|
if [[ ${#current_values[@]} -eq 0 ]]; then
|
|
FLAG_GROUPS["$current_flag"]="true"
|
|
else
|
|
FLAG_GROUPS["$current_flag"]="${current_values[*]}"
|
|
fi
|
|
fi
|
|
current_flag="${token#--}" # Remove leading "--"
|
|
current_values=()
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Case 3: -short or -grouped flags (-x or -abc)
|
|
# -------------------------------------------------------------------------
|
|
elif [[ "$token" == -* && "$token" != "--" ]]; then
|
|
# Save previous group
|
|
if [[ -n "$current_flag" ]]; then
|
|
if [[ ${#current_values[@]} -eq 0 ]]; then
|
|
FLAG_GROUPS["$current_flag"]="true"
|
|
else
|
|
FLAG_GROUPS["$current_flag"]="${current_values[*]}"
|
|
fi
|
|
current_flag=""
|
|
current_values=()
|
|
fi
|
|
|
|
local chars="${token#-}"
|
|
|
|
if [[ "${#chars}" -gt 1 ]]; then
|
|
# -abc → treat each letter as a boolean flag
|
|
for ((i = 0; i < ${#chars}; i++)); do
|
|
FLAG_GROUPS["${chars:i:1}"]="true"
|
|
done
|
|
else
|
|
# Single short flag (-x) may collect values
|
|
current_flag="$chars"
|
|
current_values=()
|
|
fi
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Case 4: Value (non-flag)
|
|
# -------------------------------------------------------------------------
|
|
else
|
|
current_values+=("$token")
|
|
fi
|
|
|
|
shift
|
|
done
|
|
|
|
# Final flush (for last group)
|
|
if [[ -n "$current_flag" ]]; then
|
|
if [[ ${#current_values[@]} -eq 0 ]]; then
|
|
FLAG_GROUPS["$current_flag"]="true"
|
|
else
|
|
FLAG_GROUPS["$current_flag"]="${current_values[*]}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# FUNCTION: print_grouped_args
|
|
# Description:
|
|
# Pretty-prints the FLAG_GROUPS key/value structure.
|
|
# -----------------------------------------------------------------------------
|
|
print_grouped_args() {
|
|
echo "Parsed Arguments:"
|
|
for key in "${!FLAG_GROUPS[@]}"; do
|
|
IFS=' ' read -r -a values <<<"${FLAG_GROUPS[$key]}"
|
|
echo "--$key:"
|
|
if [[ "${FLAG_GROUPS[$key]}" == "true" ]]; then
|
|
echo " [boolean flag]"
|
|
elif [[ ${#values[@]} -eq 0 ]]; then
|
|
echo " [empty]"
|
|
else
|
|
for i in "${!values[@]}"; do
|
|
echo " [$i]: ${values[$i]}"
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# TEST CASE (for development)
|
|
# Comment this out to use real CLI args
|
|
# -----------------------------------------------------------------------------
|
|
#set -- --name Kerem yollu siki --age=33 --flag -vx --output result.txt -t alpha beta
|
|
|
|
# Run parser and print results
|
|
#parse_grouped_args "$@"
|
|
#print_grouped_args
|