Bash – Ways to Set Positional Parameters

bash

From https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin

set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument …]
set [+abefhkmnptuvxBCEHPT] [+o option-name] [argument …]

-- If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the
arguments, even if some of them begin with a ‘-’.

- Signal the end of options, cause all remaining arguments to be assigned to the positional parameters. The -x and -v options are
turned off. If there are no arguments, the positional parameters
remain unchanged.

Using ‘+’ rather than ‘-’ causes these options to be turned off. The
options can also be used upon invocation of the shell. The current set
of options may be found in $-.

The remaining N arguments are positional parameters and are assigned,
in order, to $1, $2, … $N. The special parameter # is set to N.

It seems that there are three ways to set the position parameters:

set -- argument
set - argument
set argument

What are their differences?

Thanks.

Best Answer

The difference between -- and - is that when - is used, the -x and -v options are also unset.

$ set -vx
$ echo "$-"
himvxBHs                # The options -v and -x are set.

$ set - a b c
$ echo "$-  <>  $@"     # The -x and -v options are turned off.
himBHs  <>  a b c

That's the usual way in which shells accepted the -, however, in POSIX, this option is "unspecified":

If the first argument is '-', the results are unspecified.

The difference between set -- and plain set is quite commonly used.
It is clearly explained in the manual:

-- If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the args, even if some of them begin with a -.

The -- signals the "end of options" and any argument that follows even if it start with a - will be used as a Positional argument.

$ set -- -a -b -e -f arg1
$ echo "$@"
-a -b -e -f arg1

Instead:

$ set -a -b -e -f arg1
$ echo "$@"
arg1

But also some shell options have changed.

Not using any of - or -- will allow the setting of set options with variables that expand to options names (even if quoted):

$ echo "$-"
himBHs

$ a='-f'
$ set "$a"

$ echo "$-"
fhimBHs
Related Question