Velvet Star Monitor

Standout celebrity highlights with iconic style.

news

Warnings about invalid options names that occur between valid option names

Writer 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 -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
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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy