So I have a script where I want to process options with getopts
but I also want to read arguments to the program itself in the usual way. So in this example script, I want to process the options and then echo
the argument, given like ./script.sh -abc theargument
. The problem that arises is that I don't know which shell argument is it. Argument isn't supposed to be related to the options, so you can call the script like ./script.sh theargument
as well:
#!/bin/sh
while getopts "abc" opt; do
case $opt in
a) echo "option a" ;;
b) echo "option b" ;;
c) echo "option c" ;;
esac
done
echo # what?
I can't just shift
arguments with $OPTIND
to make it $1
because options can be given like -abc
, -a -b -c
, -ab -c
etc., so number of options doesn't correspond to the number of arguments.
Ideally I'd want to avoid bashisms
The bash
way is to use indirection with ${!VARIABLE}
- what VARIABLE
expands to is treated as the parameter to use, so echo "${!OPTIND}"
after the while loop in your example would display theargument
.
The more generic way is to use shift
to discard the option arguments and then use $1
etc.:
if [ "$OPTIND" -gt 1 ]; then
shift $((OPTIND - 1))
fi
In your example $OPTIND
is 2 after the loop, so this will shift the positional parameters left by 1, discarding the -abc
and leaving theargument
in $1
. This approach works if you use -abc theargument
, -ab -c theargument
, -a -b -c theargument
, and so on.