How do I parse optional arguments in a bash script if no order is given?
This article shows two different ways - shift
and getopts
(and discusses the advantages and disadvantages of the two approaches).
With shift
your script looks at $1
, decides what action to take, and then executes shift
, moving $2
to $1
, $3
to $2
, etc.
For example:
while :; do
case $1 in
-a|--flag1) flag1="SET"
;;
-b|--flag2) flag2="SET"
;;
-c|--optflag1) optflag1="SET"
;;
-d|--optflag2) optflag2="SET"
;;
-e|--optflag3) optflag3="SET"
;;
*) break
esac
shift
done
With getopts
you define the (short) options in the while
expression:
while getopts abcde opt; do
case $opt in
a) flag1="SET"
;;
b) flag2="SET"
;;
c) optflag1="SET"
;;
d) optflag2="SET"
;;
e) optflag3="SET"
;;
esac
done
Obviously, these are just code-snippets, and I've left out validation - checking that the mandatory args flag1 and flag2 are set, etc.
Which approach you use is to some extent a matter of taste - how portable you want your script to be, whether you can live with short (POSIX) options only or whether you want long (GNU) options, etc.
use an array.
#!/bin/bash
args=( --flag1 "$1" --flag2 "$2" )
[ "x$3" = xFALSE ] || args+=( --optflag1 "$3" )
[ "x$4" = xFALSE ] || args+=( --optflag2 "$4" )
[ "x$5" = xFALSE ] || args+=( --optflag3 "$5" )
[ "x$6" = xFALSE ] || args+=( --optflag4 "$6" )
[ "x$7" = xFALSE ] || args+=( --optflag5 "$7" )
program_name "${args[@]}"
this will handle arguments with spaces in them correctly.
[edit] I was using the roughly eqivalent syntax args=( "${args[@]}" --optflag1 "$3" )
but G-Man suggested a better way.