Score:0

Warnings about invalid options names that occur between valid option names

jp flag

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
bac0n avatar
cn flag
Left side parentheses should not be there. You do not have to quote the pattern either, If you don't have the intention of manipulating `$@` (positional parameters) there is no need to re-assign them to another array. (case `"$i"` in... should be quoted though)
bac0n avatar
cn flag
`printf 'Invalid option: %s\n' "$i"`
jp flag
The question is about detecting invalid options that occur between valid option arguments.
bac0n avatar
cn flag
You will still have to fix what I pointed out
jp flag
Using "$i" with `case` is not required. Yes I could simply do `for i in "$@"; do`, right?
Score:1
cn flag

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

jp flag
Would using `;;` instead of `;&` still do the same thing?
bac0n avatar
cn flag
I will will out with another solution with getopt ... `;&` acts as a pass-through. I think it makes it more readable
jp flag
Do not intend to spoil your plan, but I am avoiding using `getopt` or `getopts`. I have used them before, but I do more things than what they currently provide.
bac0n avatar
cn flag
overly complexed.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.