I want to use both getopts
and positional parameters, but if I pass in a positional parameter to the program the getopts
get lost.
directory=$1
while getopts l: flag; do
case "$flag" in
l) level=$OPTARG;;
esac
done
if [ -n "$level" ]; then
echo "Level exist!"
else
echo "Level doesn't exist!"
fi
So when I run the program like this:
sh myprogram.sh ~/documents -l 2
I expect:
Level exist!
And instead it returns:
Level doesn't exist!
The thing is, if I run the program without the positional parameter (~/documents) like this:
sh myprogram.sh -l 2
I get the correct output:
Level exist!
Why is that? How can I use both positional parameters and getopts
in bash?
Thanks!
Yes. I want to enable my script to handle a mix of positional parameters and getopt values. everything which is remaining from getopt should be passed with underlying shell script. Only the first line is compliant with the unix standards (see below) for option processing. Doing it otherwise will be a lot more work to get right, and to maintain.
With getopts, the Bash shell is running your script and the Bash shell is doing the option parsing. You don’t need to invoke an external program to handle the parsing. The tradeoff is getopts doesn’t handle double-dashed, long-format option names. So you can use options formatted like -w but not ” ---wide-format .”
The options expected by getopts are -a, -p, and -Z, with no arguments. These options can be combined in any order as -aZ, -pa, -Zap, etc. Let's say that you'd like the -a and -Z options to take arguments. You can specify this by putting a colon (": ") after that option in optstring.
If the option is expecting an argument, getopts gets that argument, and places it in $OPTARG. If an expected argument is not found, the variable optname is set to a colon (": "). Getopts then increments the positional index, $OPTIND, that indicates the next option to be processed.
Most tools are written in the form: tool [options] arg ...
So you would do this:
# first, parse the options:
while getopts l: flag; do
case "$flag" in
l) level=$OPTARG;;
\?) exit 42;;
esac
done
# and shift them away
shift $((OPTIND - 1))
# validation
if [ -n "$level" ]; then
echo "Level exist!"
else
echo "Level doesn't exist!"
fi
# THEN, access the positional params
echo "there are $# positional params remaining"
for ((i=1; i<=$#; i++)); do
printf "%d\t%s\n" $i "${!i}"
done
Use the \?
to abort the script if the user provides an unknown option or fails to provide a required argument
And invoke it like:
$ bash test.sh
Level doesn't exist!
there are 0 positional params remaining
$ bash test.sh -l 2
Level exist!
there are 0 positional params remaining
$ bash test.sh -l 2 foo bar
Level exist!
there are 2 positional params remaining
1 foo
2 bar
$ bash test.sh -x
test.sh: illegal option -- x
$ bash test.sh -l
test.sh: option requires an argument -- l
But you cannot put the options after the arguments: getopts stops when the first non-option argument is found
$ bash test.sh foo bar -l 2
Level doesn't exist!
there are 4 positional params remaining
1 foo
2 bar
3 -l
4 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With