Bourne | Ash |  #!  | find | ARG_MAX | Shells | 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 set both arguments ("set arg1 arg2 ...") and options, sometimes also called flags (e.g. "set -e" for exit upon error).

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

set -- was not implemented originally, though. Here are some parts of the history:


There's another reason, why you will see "#!/bin/sh -", it also 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.


Endnote: code comparison about the "-" bug:

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;