Bourne | Ash |  #!  | find | ARG_MAX | Shells | whatshell | portability | permissions | UUOC | ancient | - | ../Various | HOME
"$@" | echo/printf | set -e | test | tty defs | tty chars | $() vs ) | IFS | using siginfo | nanosleep | line charset | locale


Separating arguments from options


The command "set" is used to both set arguments (set arg1 arg2 ...) and options (e.g. set -e for exit upon error), sometimes also called flags.

It is necessary to distinguish options from arguments, to be able to use arguments with leading dashes.
Nowadays, this is usually achieved by using -- as delimiter (set -e -- -arg1 -arg2).

Yet, this is frequently seen with a single dash as delimiter. Why?

set -- was not implemented originally, but came with the second release of the Bourne shell. Apparently, it gets confused since then.


Another reason to end options

At the beginning of some scripts you will see an equivalent to set --,

"#!/bin/sh --" or "#!/bin/sh -".

This fixes a security hole. The problem is as follows

If the script doesn't force end of options, you will get an interactive shell:
The kernel starts the the interpreter with the script as argument, which is -i.

Be aware, that your shell might change the path from -i to ./-i, like bash does (all releases).
Bourne, Korn and Almquist shells, pdksh (and its derivatives) keep the path.


Other issues

By the way, there's an alternative to set --, you could use a dummy and shift it away:

    set -options dummy arguments; shift
And there's another meaning of "set --":

Modern bourne compatible shells allow to unset the parameter list this way.
However, in the traditional Bourne shell this doesn't change anything.
Alternatively, you can either shift until there are no parameters left,

    while shift 2>/dev/null; do :; done

or similar to the abovementioned workaround

    set -options dummy; shift


Endnote: code comparison about the "-" bug

The following was released under the license of Caldera.

Version 7

    INT     options(argc,argv)
	    STRING          *argv;
	    INT             argc;
    {
	    REG STRING      cp;
	    REG STRING      *argp=argv;
	    REG STRING      flagc;
	    STRING          flagp;


	    IF argc>1 ANDF *argp[1]=='-'
	    THEN    cp=argp[1];
		    flags &= ~(execpr|readpr);
		    WHILE *++cp
		    DO      [...]

System III

    INT     options(argc,argv)
	    STRING          *argv;
	    INT             argc;
    {
	    REG STRING      cp;
	    REG STRING      *argp=argv;
	    REG STRING      flagc;
	    STRING          flagp;

	    IF argc>1 ANDF *argp[1]=='-'
	    THEN
		    IF argp[1][1] == '-'
		    THEN    /* if first argument is "--" then options are not
			       to be changed        Fix for problems getting
			       $1 starting with a "-"
			    */
			    argp[1] = argp[0]; argc--;
			    return(argc);
		    FI
		    cp = argp[1];
		    IF cp[1] == '\0' THEN flags &= ~(execpr|readpr) FI
		    /* Step along 'flagchar[]' looking for matches.
		       'sicr' are not legal with 'set' command.
		    */
		    WHILE *++cp
		    DO      flagc=flagchar;