Sample Header Ad - 728x90

Handling long-options with getopts

4 votes
2 answers
16856 views
I am parsing options with getopts but would like to handle long-options as well. print-args () { title="$1" ; shift printf "\n%s\n" "${title}: \$@:" for arg in "$@"; do (( i = i + 1 )) printf "%s |%s|\n" "${i}." "$arg" done } getopts_test () { aggr=() for arg in "$@"; do case $arg in ("--colour"|"--color") aggr+=( "-c" ) ;; ("--colour="*|"--color="*) aggr+=( "-c" "${arg#*=}" ) ;; (*) aggr+=( "$arg" ) ;; esac done print-args "print" "$@" eval set -- "${aggr[@]}" print-args "eval" "$@" set -- "${aggr[@]}" print-args "set" "$@" local OPTIND OPTARG local shortopts="C:" while getopts "$shortopts" arg; do case $arg in ("c") context="$OPTARG" ;; (*) break ;; esac done shift $(( OPTIND - 1 )) } But I wonder whether the use of set -- "${aggr[@]}" is correct. Or is the following (using eval) more appropriate? eval set -- "${aggr[@]}" I have performed a test shown below. With eval, the string "Gunga Din" is split up, whereas with set -- "${aggr[@]}", it is being parsed correctly as a single string. getopts_test -f -g 130 --colour="170 20" "Gunga Din" print: $@: 1. |-f| 2. |-g| 3. |130| 4. |--colour=170 20| 5. |Gunga Din| eval: $@: 1. |-f| 2. |-g| 3. |130| 4. |-c| 5. |170| 6. |20| 7. |Gunga| 8. |Din| set: $@: 1. |-f| 2. |-g| 3. |130| 4. |-c| 5. |170 20| 6. |Gunga Din| Then I ran another function that uses the non-GNU getopt. getopt_test () { shortopts="Vuhv::H::w::e::n::l::C:" shortopts="${shortopts}bgcrmo" longopts="version,usage,help,verbosity::" longopts="${longopts},heading::,warning::,error::" longopts="${longopts},blu,grn,cyn,red,mgn,org" opts=$( getopt -o "$shortopts" -l "$longopts" -n "${0##*/}" -- "$@" ) print-args "\$@:" "$@" print-args "opts:" "$opts" set -- "$opts" print-args "set -- \"$opts\"" "$@" eval set -- "$opts" print-args "eval set -- \"$opts\"" "$@" } This resulted in the following getopt_test --warning=3 "foo'bar" "Gunga Din" $@: 1. |--warning=3| 2. |foo'bar| 3. |Gunga Din| opts: 1. | --warning '3' -- 'foo'\''bar' 'Gunga Din'| set -- "$opts" 1. | --warning '3' -- 'foo'\''bar' 'Gunga Din'| eval set -- "$opts" 1. |--warning| 2. |3| 3. |--| 4. |foo'bar| 5. |Gunga Din| As shown the result of getopt is a single entry with positional arguments re-arranged. This shows the need to use eval set -- "$opts" to split the positional arguments in the opts string into five entries for option parsing and processing.
Asked by Vera (1363 rep)
Oct 30, 2021, 09:46 AM
Last activity: Dec 18, 2023, 04:43 PM