How can I detect that no options were passed with getopts?
Solution 1
When you run this script without any options, getopt will return false, so it won't enter the loop at all. It will just drop down to the print - is this ksh/zsh?
If you must have an option, you're best bet is to test $name after the loop.
if [ -z "$name" ]
then
usage
exit
fi
But make sure $name
was empty before calling getopts
(as there could have been a $name
in the environment the shell received on startup) with
unset name
(before the getopts
loop)
Solution 2
getopts
processes the options in turn. That's its job. If the user happens to pass no option, the first invocation of getopts
exits the while loop.
If none of the options take an argument, the value of OPTIND
indicates how many options were passed. In general, OPTIND
is the number of arguments that are options or arguments to options, as opposed to non-option arguments (operands).
while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"
In any case, you're not trying to determine whether there were no options, but whether none of the name
-setting options were passed. So check if name
is unset (and take care to unset it first).
Solution 3
I would check it with a variable. If getopts never passes the loop in case of no argument, you can use that for example like this:
#getoptDemo.sh
usage()
{
echo "usage: <command> options:<w|l|h>"
}
no_args="true"
while getopts wlh: option
do
case $option in
(w)
name='1';;
(l)
name='2';;
(h)
name='3';;
(*)
usage
exit;;
esac
no_args="false"
done
[[ "$no_args" == "true" ]] && { usage; exit 1; }
print 'hi'$name
Solution 4
If your script must receive option arguments is any case, place this block in the beginning (before getops).
if [[ ! $@ =~ ^\-.+ ]]
then
#display_help;
fi
Block checks that parameter string not begins with -
symbol, what indicates that first parameter is not an option argument.
![Hussain Tamboli](https://i.stack.imgur.com/IfV2L.jpg?s=256&g=1)
Hussain Tamboli
About me Full Stack Developer at LAZADA Linkedin
Updated on September 18, 2022Comments
-
Hussain Tamboli almost 2 years
I have this code -
#getoptDemo.sh usage() { echo "usage: <command> options:<w|l|h>" } while getopts wlh: option do case $option in (w) name='1';; (l) name='2';; (h) name='3';; (*) usage exit;; esac done print 'hi'$name
When I run
bash getoptDemos.sh
(without the option) it printshi
instead of calling the functionusage
. It calls usage when options other than w, h and l are given. Then can't it work when no options are specified.I have tried using
?
,\?
,:
in place of*
but I can't achieve what I wanted to. I mean all thedocs
ongetopt
says it to use?
.What am I doing wrong?
-
Admin over 11 yearsWhat shell are you running it under?
-
Admin over 11 yearsI am running it under
/bin/bash
-
Admin over 10 yearsOther alternatives: wiki.bash-hackers.org/howto/getopts_tutorial
-
-
Hussain Tamboli over 11 yearsno. its bash. So how do i achieve what I want - handle the
no argument
condition using bash. -
Yoshidk over 11 yearsIf you want a mandatory option, I don't think thats possible - its probably why they are called options :) You can test $name though, after the loop to make sure it has been set. if [ -z "$name" ] ; then usage; exit ; fi
-
Hussain Tamboli over 11 yearsthanks. the above code really helped. Its too bad
getopts
doesn't have such provision. What's worse than that is can't upvote you. -
Hussain Tamboli over 11 yearswhat if I was running other shell? zsh, sh. does any shell other than bash take care of this condition?
-
Hussain Tamboli over 11 yearsthanks. +1 for you. when I put the last 3 lines from your code in sample.sh and run
bash sample.sh -abc file.txt
it gives -1 non-option arguments
. how do I find out how many options were given. (here 3) -
Daniel about 9 yearsStrange no one has commented on this slight bug -- if no options are given, OPTIND will be 1 after that 'while getopts ...' loop. Thus the if check should check equality with 1, not zero.
-
Vincent Gerris about 3 yearsyou need to remove the () behind the usage call