Warnings about invalid options names that occur between valid option names
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 -w
But 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
Solution 1:
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