UPDATED: Long options with arguments in the "name=value" style. The original post neglected this important case.
For years I've never know quite the right way to handle long options in Bash without significant, ugly coding. The usual sources (Advanced Bash-Scripting Guide, The Bash Hackers Wiki, others) are not much help. An occasional glimpse appears on StackOverflow, but not well explained or voted.
Solution
Working with a colleague yesterday, we found this:
name=Bob while getopts :hn:-: opt do [[ - == $opt ]] && opt=${OPTARG%%=*} OPTARG=${OPTARG#*=} case $opt in h | help ) print_help ; exit 0 ;; n | name ) name=$OPTARG ;; * ) print_usage >&2 ; exit 2 ;; esac done shift $((OPTIND - 1)) echo "$0: $name"
$ ./try-me -h Usage: ./try-me [-h|--help][-n|--name <name>] $ ./try-me --help Usage: ./try-me [-h|--help][-n|--name <name>] $ ./try-me -n Fred ./try-me: Fred $ ./try-me --name=Fred ./try-me: Fred
Magic!
I checked with bash 3.2 and 4.3. At least for these, the '-' option argument has a bit of magic when it takes an argument. When the argument to '-' starts with a dash, as in --help
(here "-help" is the argument to the '-' option), getopts
drops the argument's leading '-', and OPTARG
is just the text ("help" in this example). Only '-' has this magic.
Add a quick check for '-' at the top of the while-loop, and the case-block is simple and clear.
Bob's your uncle.
UPDATE: Followup on Bash long options.