4

I followed the tutorial here to learn how to use getopts. I'm able to execute all the options properly provided by the user. But now I want to execute a default option when none of the options are provided.

For e.g:

while getopts ":hr" opt; do
    case $opt in
        h )
            show_help;
            exit 1
            ;;
        r )
          echo "Default option executed"
          ;;
    esac
done

So, if the user provides with either -h or -r, the corresponding commands should be executed (which actually does) but when none of these options are provided -r should be executed by default. Is there a way to achieve this?

UPDATE

I tried cas's suggestion and included *) to my getopts function but nothing seems to be happening.

while getopts ":hr" opt; do
    case $opt in
        h )
            show_help;
            exit 1
            ;;
        r )
          echo "Default option executed"
          ;;

        \? )
          echo error "Invalid option: -$OPTARG" >&2
          exit 1
          ;;

        : )
          echo error "Option -$OPTARG requires an argument."
          exit 1
          ;;

        * )
          echo "Default option executed"
          ;;
    esac
done

Is there something wrong with this snippet?

  • does my answer make sense? the "while" loop is exiting when getopts doesn't have any options to parse, so the case statement is never seen. – Jeff Schaller Jun 2 '16 at 16:10
  • the 2nd snip looks ok. when you say it does nothing, does h and r still work or not? – Skaperen Nov 18 '18 at 5:08
2

Adding a default option to the case statement won't help because it won't be executed if getopts doesn't have options to parse. You can see how many options it processed with the OPTIND shell variable. From help getopts:

Each time it is invoked, getopts will place the next option in the
shell variable $name, initializing name if it does not exist, and
the index of the next argument to be processed into the shell
variable OPTIND.  OPTIND is initialized to 1 each time the shell or
a shell script is invoked.

So if OPTIND is 1, no options were processed. Add this after your while loop:

if (( $OPTIND == 1 )); then
   echo "Default option"
fi
0

Bash's getopts will exit the while loop when no options are provided, setting $opt to '?'. To determine this situation in a script, add an if clause after your while loop, similar to:

if [ "$opt" = "?" ]
then
  echo "Default option executed (by default)"
fi

For reference, see Bourne Shell Builtins

0

From what I see, r is not expecting an argument. Logically, no matter what happens, r is executed the same way.

I would take the command associated with r out of the getopts clause and have it execute regardless. That would suffice for your requirements I believe. In other words, put the echo statement after the "done" statement.

You can leave r in getopts as a stub if you wish for compatibility or other reasons.

You can also add a variable set to zero as a switch. As soon as any option other than r is selected, you have a line that changes that variable to 1. After the done statement, you can write " if variable equals zero, execute default command".


I think I like Cas' answer the best. I wanted to comment but I do not have the privileged. I'll build on his idea. This is the same as what Cas proposed, but you only have one command ( so you don't have double the same command and make a mistake in the future), and it will give you the possibility of also using it in addition to -h.

DEF="Default command executed"
while getopts ":hr" opt;
   do case $opt in 
     h) show_help; 
        exit 1 ;; 
     r) echo "$DEF" ;; 
     *) echo "$DEF" ;; 
  esac
done
  • You could remove the echo command and replace it with these three. top: SWITCH=0 h section (line 4 or 5): SWITCH=1 end: [ “$SWITCH” == “0”” ] && echo “Default option executed” – BloodyEl Jun 2 '16 at 12:26
0

Use the getopts loop to set variables based on what parameters are passed. Then act on these variables:

#!/bin/sh

# Defaults:
do_help=0
do_r=0

while getopts "hr" opt; do
    case $opt in
        h) do_help=1 ;;
        r) do_r=1    ;;
        *) echo 'Error in command line parsing' >&2
           exit 1
    esac
done

if [ "$do_help" -eq 1 ]; then
    show_help
    exit
fi

printf 'Default option executed (r=%d)\n' "$do_r"

I opted for letting the code exit successfully if -h is used (unless show_help fails) rather than with a non-zero exit status (asking for help is not an error).

Running it:

$ sh script.sh -r
Default option executed (r=1)
$ sh script.sh
Default option executed (r=0)
$ sh script.sh -h
script.sh[24]: show_help: not found

This has the benefit of separating the command line parsing code from the rest of the logic of your script.

It also allows you to do basic sanity checks after the loop while keeping the actual parsing loop short and simple. For example:

# command line parsing loop above here

if [ "$do_help" -eq 1 ] && [ "$do_r" -eq 1 ]; then
    echo 'Options -h and -r are mutually exclusive' >&2
    exit 1
fi

# code that acts on user-supplied options below
0

You can use number of arguments as well:

if [ "$#" == 0 ]; then
  usage
  exit 1
fi

More info here: http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.