When you write the command line parsing bit of your code, you specify what options take arguments and which ones do not. For example, in a shell script accepting an
-h option (for help for example) and an
-a option that should take an argument, you do
opt_h=0 # default value
while getopts 'a:h' opt; do
case $opt in
h) opt_h=1 ;;
a) opt_a="$OPTARG" ;;
echo "h: $opt_h"
echo "a: $opt_a"
a:h bit says "I'm expecting to parse two options,
-a should take an argument" (it's the
a that tells the parser that
-a takes a argument).
Therefore, there is never any ambiguity in where an option ends, where its value starts, and where another one starts after that.
$ bash test.sh -h -a hello
$ bash test.sh -h -ahello
$ bash test.sh -hahello
This is why you most of the time shouldn't write your own command line parser to parse options.
There is only one case in this example that is tricky. The parsing usually stops at the first non-option, so when you have stuff on the command line that looks like options:
$ bash test.sh -a hello -world
test.sh: illegal option -- w
test.sh: illegal option -- o
test.sh: illegal option -- r
test.sh: illegal option -- l
test.sh: illegal option -- d
The following solves that:
$ bash test.sh -a hello -- -world
-- signals an end of command line options, and the
-world bit is left for the program to do whatever it wants with (it's in one of the positional variables).
That is, by the way, how you remove a file that has a dash in the start of its file name with
Utilities written in C call
getopt() (declared in
unistd.h) which works pretty much the same way. In fact, for all we know, the
getopts may be implemented using a call to the C library function
getopt(). Perl, Python and other languages have similar command line parsing libraries, and it is most likely that they perform their parsing in similar ways.
Some of these
getopt-like library routines also handle "long" options. These are usually preceded by double-dash (
--), and long options that takes arguments often does so after an equal sign, for example the
--block-size=SIZE option of [some implementations of] the
du utility (which also allows for
-B SIZE to specify the same thing).
The reason manuals are often written to show a space in between the short options and their arguments is probably for readability.
EDIT: Really old tools, such as the
tar utilities, have options without dashes in front of them. This is purely for historical reasons and for maintaining compatibility with software that relies on them to work in exactly that way. The
tar utility has gained the ability to take options with dashes in more recent times. The BSD manual for
tar calls the old-style options for "bundled flags".