6

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.

4
  • 2
    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? Oct 17, 2014 at 15:12
  • 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.
    – Cold
    Oct 17, 2014 at 15:14
  • @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?
    – terdon
    Oct 17, 2014 at 15:32
  • 2
    @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.
    – jw013
    Oct 17, 2014 at 19:36

3 Answers 3

6

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

1

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

0

One method for putting the optional argument at the start is using shift.
What it does is move all arguments n number of steps to the left, removing the ones going below $1. With no argument given to shift, the number of steps is 1.

At the beginning of the script you check whether the first argument matches the structure of the optional one or the first required argument.
If it's the required one you do nothing.
If it's the optional one you handle it and call shift.

The useful thing here, is that regardless of whether the optional argument is given or not, the required arguments, say there's 3, will always be at $1 to $3 after the block where the optional argument is handled.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .