I have a script with a long list of OPTIONAL arguments. some have associated values.
Such as:
.script --first 2012-12-25 --last 2012-12-26 --copy --remov
getopts cannot have optional arguments it seems. otherwise great.
my solution
loop the $@
and setting a variable equal to x=$arg
do the case switch on that variable (rather than arg)
that worked fine for arguments of the type --startdate 2012-12-25 --enddate 2012-12-29
but did not work for --remove
that has no following argument.
therefore tack on stuff (unlikely argument) onto the arg string.
leaving the following
argc="$@ jabberwhocky"
echo $argc
x=0
# x=0 for unset variable
for arg in $argc
do
case $x in
"--start" )
STARTDATE=$arg ;;
"--end" )
ENDDATE=$arg ;;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
... and so on....
esac
x=$arg
done
You can allow both --a=arg or -a arg options with a little more work:
START_DATE="$(date '+%Y-%m-%d')";
LAST_DATE="$(date '+%Y-%m-%d')";
while [[ $# -gt 0 ]] && [[ "$1" == "--"* ]] ;
do
opt="$1";
shift; #expose next argument
case "$opt" in
"--" ) break 2;;
"--first" )
START_DATE="$1"; shift;;
"--first="* ) # alternate format: --first=date
START_DATE="${opt#*=}";;
"--last" )
LAST_DATE="$1"; shift;;
"--last="* )
LAST_DATE="${opt#*=}";;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
"--optional" )
OPTIONAL="$optional_default";; #set to some default value
"--optional=*" )
OPTIONAL="${opt#*=}";; #take argument
*) echo >&2 "Invalid option: $@"; exit 1;;
esac
done
Note the --optional argument uses a default value if "=" is not used, else it sets the value in the normal way.
If you have more than one option, and especially options with values mixed with options without values, let getopts do the work for you.
Use shift
in the end of each case
statement.
Quote from a bash
manual:
shift [n]
The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is 0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater than $# or less than zero; otherwise 0.
$@
is an array, & not a simple variable.
You can capture it to a local variable as x=("$@")
& then use array x with indices as 0 to ($# - 1)
.
To access individual elements, use ${x[$i]}
. You can NOT directly use ${@[$i]}
, however.
So instead of for arg in "$@"
loop, you will have i=0; while [ $i -lt $# ]; do
loop.