Here's how I'd do it. You can have many several non-optional arguments placed anywhere.
#!/bin/bash
while [ $# -gt 0]; do
while getopts ":a:p:drh" opt; do
case "$opt" in
a) echo $OPTARG; shift;;
p) echo $OPTARG; shift;;
d) echo Option d;;
r) echo Option r;;
h) echo Option h;;
\?) echo unknown Option;;
:) echo missing required parameter for Option $OPT;;
esac
shift
OPTIND=1
done
if [ $# -gt 0 ]; then
POSITIONALPARAM=(${POSITIONALPARAM[@]} $1)
shift
OPTIND=1
fi
done
echo ${POSITIONALPARAM[@]}
The inner loop parses the parameters. Whenever a non-option parameter is encountered, it will exit the inner loop. The external loop will grab the next non-option parameter. The inner loop will then pickup after the non-option parameter is removed then resumes reading the next optional parameters and so on.
As Chrono Kitsune suggested that I explain, the shift removes the first argument (optional or not) and moves everything one position to the left. $1
is removed, $2
becomes $1
, $3
becomes $2
so on and so forth. This gives the script the control to move the non-optional argument until it becomes $1
.
Both shift
and resetting OPTIND
make this possible. Thanks to Chrono Kitsune for the suggestion that OPTIND should be reset to 1 instead of 0.
./sample.bash -a one -p two more -d sample
Output:
one
two
Option d
more sample
Now let's call the script with arguments in different positions.
./sample.bash more -a one -p two -d sample
Output:
one
two
Option d
more sample