Optional arguments after or before the mandatory arguments?

20,896

Solution 1

If you're fine with the optional arguments being at the end, you can just do this:

foo=$1
bar=$2
baz=${3:-default value}

That will store the first two arguments in $foo and $bar. If a third argument was provided, it will be stored in $baz; otherwise it will default to default value. You can also just check if the third variable is empty:

if [ -z "$3" ]; then
    # Code for the case that the user didn't pass a third argument
fi

If you want the defaults at the beginning, the easiest way is probably to check the number of arguments passed to the script, which is stored in $#. For example:

case $# in
  2)
    # Put commands here for when the user passes two arguments
    # Could just be setting variables like above, or anything else you need
    ;;
  3)
    # Put commands here for when the user passes three arguments
    ;;
  *)
    echo "Wrong number of arguments passed"
    exit 1;;
esac

Switching on $# will work fine for either case, if you want error checking. If your script uses getopt-style arguments like the cut example, you could use that; see this Stack Overflow question for more information

Solution 2

There are two different concepts: mandatory vs optional arguments, and options vs operands. Options are arguments that start with -, operands are arguments that don't start with - and aren't the argument of an option. Options are identified by their name and can normally be in any order. Operands are identified by their position. So in

someprogram -a -z -c foo bar

there are three options -a, -c and -z, and there are two operands, the first being foo and the second being bar.

Options normally go before operands. GNU programs tend not to care about the order, while most non-GNU programs treat arguments starting with - as operands if there is another operand before them. There are many variations on options (grouping, --, etc.) which I won't go into here.

If your program takes two mandatory operands and a third optional operand, then the natural way is for the mandatory operands to be the first one and the second one, and the third operand be the optional one if present.

In a shell script, the arguments are "$1", "$2", "$3", etc. The number of arguments is $#. If your script doesn't recognize any option, you can leave out option detection and treat all arguments as operands. See Michael Mrozek's answer for sample code. If you do want to recognize options, use the getopts builtin (see your shell's documentation for examples).

Share:
20,896

Related videos on Youtube

Cold
Author by

Cold

Updated on September 18, 2022

Comments

  • Cold
    Cold almost 2 years

    I'm creating a shell script and I need it to take two mandatory arguments and one optional. How do I check that? In most scripts I've seen, the optional arguments are passed before the mandatory ones, like:

    cut -c2 test.txt
    

    But for me this pattern would be complicated to check in the script, so my idea is to consider the third argument as optional.

    • Michael Mrozek
      Michael Mrozek over 9 years
      For what it's worth, virtually all programs that take arguments that way won't care about the order (they frequently use getopt, which handles all that); you can do cut test.txt -c2 and get the same result. If you don't care about the order, putting the optional arguments at the end seems trivial, so I'm not sure what your question is. Are you asking if there's an easy way to handle optional arguments at the beginning?
    • Cold
      Cold over 9 years
      Thanks for editing @MichaelMrozek. I wonna know if there's an easy way to handle optional arguments? The order that the user give is not important.
    • terdon
      terdon over 9 years
      @Cold it all depends on the code you are using. What language is this in, bash or another shell? How are you reading the arguments?
    • jw013
      jw013 over 9 years
      @MichaelMrozek The POSIX standard getopts actually expects all option arguments to come before non-option arguments ("operands"). The script itself has to do extra work to support interleaving the two. I do not know about getopt since it is less standard and there are multiple (GNU and not GNU) versions out there.