我已经编写了以下 bash 片段,但需要实现一些更复杂的东西。
任务是仅当无效选项发生在已知选项之间时才检测它。
例如,下面myfunc -v -w --vlt "Ubuntu"
会打印
Unknown option -w
但myfunc -v --vlt -w "Ubuntu"
不会打印任何警告消息,因为-w
它发生在已知的非选项参数之后。
代码只会检查以 开头的选项名称-
。因此,myfunc -v -w 5 --vlt "Ubuntu"
只会报告-w
,而忽略警告消息的任何选项值。
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
答案1
在这种情况下,最好切换策略和shift
选项,因为无法在 for 循环中获取列表位置,这使得几乎不可能检查具有值的选项:
#!/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