Reputation: 3738
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 --remove
.script --first 2012-12-25
Thus the following case statement:
for arg in "$@"
do
case $arg in
"--first" )
START_DATE=$arg;;
"--last" )
END_DATE=$arg;;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
# ... and so on
esac
done
that needs a increment $arg+1
type statement to get the following arg (in some cases).
How is that possible?
I'm also happy to do a substring such .script --first2012-12-25 --last2012-12-26
and not sure how to proceed there.
Upvotes: 27
Views: 65418
Reputation: 3776
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.
Upvotes: 34
Reputation: 3738
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
Upvotes: 1
Reputation: 1798
If you have more than one option, and especially options with values mixed with options without values, let getopts do the work for you.
Upvotes: 1
Reputation: 20980
$@
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.
Upvotes: 2
Reputation: 30167
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.
Upvotes: 2