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).
getopt, which handles all that); you can docut test.txt -c2and 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?getoptsactually 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 aboutgetoptsince it is less standard and there are multiple (GNU and not GNU) versions out there.