0

The input to my shell should follow the following signature.

myscript.sh var1 var2 [-o var3] [-r var4].

The -o and -r are optional inputs and these options can occur at any location (between var1 & var 2 or at the start/end) but var3 will always preceed var4 if var 3 is specified. Also var1 will preceed var 2.

#!/bin/bash

case "$#" in
([01]) echo "Usage: $0 var1 var2 [-o val3] [-r val4]" >&2; exit 1;;
esac

VAR1="$1"
VAR2="$2" 
VAR3=
VAR4=


while getopts ":o:r:" opt; do
  case $opt in
    o)
     VAR3=$OPTARG
      ;;
    r)
     VAR4=$OPTARG 
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

shift $(( OPTIND - 1 ))


    if [ -z "${VAR3+xxx}" ] && [ -z "${VAR4+xxx}" ];
    then
    echo $1 $2;
    elif [ -z "${VAR3+xxx}" ]; 
    then
    echo $1 $2 $VAR4;
    elif [ -z "${VAR4+xxx}" ];
    then 
    echo $1 $2 $VAR3;
    else
    echo $1 $2 $VAR3 $VAR4;
    fi

How to handle the case where the optional arguments are inbetwen var1 & var2

1
  • See also SO 13070998, but this does manage to be different from that question. Commented Oct 25, 2012 at 17:13

1 Answer 1

2

Your calling convention is fighting the classic calling convention of 'options and arguments first'. So, you will need to do:

case "$#" in
([01]) echo "Usage: $0 var1 var2 [-o val1] [-r val2]" >&2; exit 1;;
esac

VAR1="$1"
VAR2="$2"
shift 2

# Now use your getopts loop...
Sign up to request clarification or add additional context in comments.

3 Comments

I don't understand ... doing VAR1 = "$1" will assign the second argument. In my case the second argument can be an optional param
What I meant was the The optional arguments can be anywhere so VAR1=$1 assumes that my non optional arguments are first. Am I right ?
If you need the extreme flexibility you're asking for, you need to co-opt the GNU getopt command — which can understand long options and which permutes options ahead of command line arguments without option letters. Or write your own version of it. If you can stick with 'mandatory options before optional options', the code above will help. If you can stick with 'mandatory options after optional options', your original code will work. Interleaving the two requires gymnastics that the standard (non-GNU) versions of getopt and getopts do not handle. Be careful with getopt vs getopts.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.