26

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 prints hi instead of calling the function usage. 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 the docs on getopt says it to use ?.

What am I doing wrong?

3
  • What shell are you running it under? Commented Oct 11, 2012 at 8:52
  • I am running it under /bin/bash Commented Oct 11, 2012 at 8:55
  • Other alternatives: wiki.bash-hackers.org/howto/getopts_tutorial Commented Oct 2, 2013 at 4:44

6 Answers 6

36

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).

2
  • 1
    thanks. +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) Commented Oct 12, 2012 at 5:14
  • 1
    Strange 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. Commented May 21, 2015 at 22:07
22

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)

4
  • no. its bash. So how do i achieve what I want - handle the no argument condition using bash. Commented Oct 11, 2012 at 8:59
  • If 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 Commented Oct 11, 2012 at 9:08
  • thanks. the above code really helped. Its too bad getopts doesn't have such provision. What's worse than that is can't upvote you. Commented Oct 11, 2012 at 9:14
  • what if I was running other shell? zsh, sh. does any shell other than bash take care of this condition? Commented Oct 11, 2012 at 10:30
7

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 
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.

1

Just before your getopts block, check to see if $1 (the first argument/option you passed on the command line) is equal to an empty string. If it is, print the usage message and exit, (or execute some "no options" function if you're an anarchist), otherwise let getopts parse the options like normal.

The reason this feature isn't included in getopts, is because you can already accomplish it in bash with an "if-else". Example:

if [[ $1 == "" ]]; then Your_Usage_Function; exit; else #parse options with getopts code block here; fi 

Make sense?

1

You should always initialize your variables before using them! This prevents already-set variables from screwing with your script, and additionally, it lets you check the status later on to ensure they were properly set.

#getoptDemo.sh usage() { echo "usage: <command> options:<w|l|h>" } name=false while getopts wlh: option do case $option in (w) name='1';; (l) name='2';; (h) name='3';; (*) usage exit;; esac done if [[ $name == false ]]; then usage(); exit 1; fi print 'hi'$name 
1
  • 1
    you need to remove the () behind the usage call Commented Jun 3, 2021 at 15:52

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.