Size: 368
Comment:
|
Size: 2843
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 7: | Line 7: |
foobar -a --busy --include something | foobar -a --include something |
Line 10: | Line 10: |
First up, there are some [[http://www.gnu.org/software/libtool/manual/libc/Argument-Syntax.html][GNU and POSIX standards]] for how to do this. | First up, there are some [[http://www.gnu.org/software/libtool/manual/libc/Argument-Syntax.html|GNU and POSIX standards]] for how to do this. === do-it-yourself === {{{ while "$1"; do case "$1" in -a|--all) ALL=yes ;shift ;; -i|--include) INCLUDE="$2"; shift; shift ;; *) echo "$PROG: Bad option '$1', exiting." >&2; exit 1;; esac done }}} This is all well and good but it's crufty and it doesn't honour the standards - for example, how do you handle concatenation of single-letter options, how about if the user writes {{{-isomething}}} without a space or {{{--include=something}}}? === getopt(1) === {{{ TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: -n 'example.bash' -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi eval set -- "$TEMP" while true ; do case "$1" in -a|--a-long) echo "Option a" ; shift ;; .../etc }}} This is better as it obeys the standards and gives the user a fairly predictable user-interface. There is still the disadvantage that options are coded in at least 2, probably 3 places - in the call to getopt(1), in the case statement that processes them and presumably in the help message that you are going to get around to writing one of these days. This is a classic opportunity for errors to creep in as the code is written and maintained - often not discovered till much, much later. === process-getopt(1) === {{{ PROG=$(basename $0) VERSION='1.2' USAGE="A tiny example using process-getopt(1)" # call process-getopt functions to define some options: source /usr/bin/process-getopt SLOT="" SLOT_func() { [ "${1:-""}" ] && SLOT="yes"; } # callback for SLOT option add_opt SLOT "boolean option" s "" slot TOKEN="" TOKEN_func() { [ "${1:-""}" ] && TOKEN="$2"; } # callback for TOKEN option add_opt TOKEN "this option takes a value" t n token number add_std_opts # define the standard options --help etc: TEMP=$(call_getopt "$@") || exit 1 eval set -- "$TEMP" # just as with getopt(1) # remove the options from the command line process_opts "$@" || shift "$?" echo "SLOT=$SLOT" echo "TOKEN=$TOKEN" echo "args=$@" }}} Here, the options are defined exactly once in the add_opt() function and its associated callback function. A lot of the dirty work is handled automatically and standards are obeyed as in getopt(1) - because it calls getopt for you. As an added bonus you get a nicely formatted help page and a starter for a man page (using a easter-egg option {{{ --print-man-page }}} ... work in progress |
How do I process options in a bash script?
For example, how do I code my bash script to accept a bunch of options like
foobar -a --include something
First up, there are some GNU and POSIX standards for how to do this.
do-it-yourself
while "$1"; do case "$1" in -a|--all) ALL=yes ;shift ;; -i|--include) INCLUDE="$2"; shift; shift ;; *) echo "$PROG: Bad option '$1', exiting." >&2; exit 1;; esac done
This is all well and good but it's crufty and it doesn't honour the standards - for example, how do you handle concatenation of single-letter options, how about if the user writes -isomething without a space or --include=something?
getopt(1)
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: -n 'example.bash' -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi eval set -- "$TEMP" while true ; do case "$1" in -a|--a-long) echo "Option a" ; shift ;; .../etc
This is better as it obeys the standards and gives the user a fairly predictable user-interface. There is still the disadvantage that options are coded in at least 2, probably 3 places - in the call to getopt(1), in the case statement that processes them and presumably in the help message that you are going to get around to writing one of these days. This is a classic opportunity for errors to creep in as the code is written and maintained - often not discovered till much, much later.
process-getopt(1)
PROG=$(basename $0) VERSION='1.2' USAGE="A tiny example using process-getopt(1)" # call process-getopt functions to define some options: source /usr/bin/process-getopt SLOT="" SLOT_func() { [ "${1:-""}" ] && SLOT="yes"; } # callback for SLOT option add_opt SLOT "boolean option" s "" slot TOKEN="" TOKEN_func() { [ "${1:-""}" ] && TOKEN="$2"; } # callback for TOKEN option add_opt TOKEN "this option takes a value" t n token number add_std_opts # define the standard options --help etc: TEMP=$(call_getopt "$@") || exit 1 eval set -- "$TEMP" # just as with getopt(1) # remove the options from the command line process_opts "$@" || shift "$?" echo "SLOT=$SLOT" echo "TOKEN=$TOKEN" echo "args=$@"
Here, the options are defined exactly once in the add_opt() function and its associated callback function. A lot of the dirty work is handled automatically and standards are obeyed as in getopt(1) - because it calls getopt for you. As an added bonus you get a nicely formatted help page and a starter for a man page (using a easter-egg option --print-man-page
... work in progress