Warnings about invalid options names that occur between valid option names
Emily Wong
I have written the following bash piece, but need to implement something a bit more complicated.
The task is to detect an invalid option only if it happens between known options.
For instance, the following myfunc -v -w --vlt "Ubuntu" would print
Unknown option -wBut myfunc -v --vlt -w "Ubuntu" would not print any warning message because -w occurs after the known non-options arguments.
The code would only check option names starting with -. Thusly myfunc -v -w 5 --vlt "Ubuntu" would only report on the -w, disregarding any option values for warning messages.
for i in "$@"; do case $i in ("-v"|"--verbosity"|"-u"|"--usage"|"-h"|"--help") printf '%s\n' "Option: $i" ;; ("--vlt"|"--blu"|"--grn"|"--ylw") printf '%s\n' "Option: $i" ;; ("--orn"|"--pur"|"--red"|"--wht") printf '%s\n' "Option: $i" ;; (*) printf '%s\n' "Invalid option | Argm: $i" ;; esac done 5 1 Answer
In this case, it's probably best to switch strategy and shift your options because there is no way to get the list position in a for-loop, which makes it almost impossible to check options with a value:
#!/bin/bash
check_value(){ ! [[ $1 = @(|-[!-]*|--[!-]*) ]]
}
expand_option(){ local -n __a__=$2; local b=${1:1} [[ ! $b =~ [\ -] ]] && { [[ $b =~ ${b//?/(.)} ]] && { __a__=("${BASH_REMATCH[@]:1}"); __a__=("${__a__[@]/#/-}"); } } || return 1
}
declare -a a=() b=()
declare -A O=()
while (($# > 0)); do case "$1" in -[!-][!-]*) expand_option "$1" a || { \ printf 'Invalid expansion: %s\n' "$1"; exit; }; set -- "${a[@]}" "${@:2}" continue ;; -[vuh]) O[${1//-}]=1 printf 'Option 1: %s\n' "$1" ;; -[!-]*) printf 'Invalid short option: %s\n' "$1" exit ;; --help) ;& --usage) ;& --verbosity) O[${1//-}]=1 printf 'Option 2: %s\n' "$1" ;; --vlt) check_value "$2" || { \ printf "Invalid value: '%s'\n" "$2"; exit; } O[${1//-}]=$2 printf 'Value for %s: %s\n' "$1" "$2" shift ;; --[!-]*) printf 'Invalid long option: %s\n' "$1" exit ;; --) b+=("${@:2}") break ;; *) b+=("$1") ;; esac shift
done
echo Final options '${O[@]}':
for k in "${!O[@]}"; do printf 'Key: %s, Value: %s\n' "$k" "${O[$k]}"
done
if ((${#b[@]} > 0)); then printf 'Unknown values: %s\n' "${b[*]}"
fi 4