Ways to set positional parameters in bash
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
The difference between set argument
and set -- argument
is common to many other commands.
You sometimes have an argument that starts with a -
, but you can't actually use it because the command thinks (because it starts with -
) that it's actually a command option.
What the --
says is effectively: "Enough! everything that follows, even if it starts with -
, is an actual argument".
Usually (according to manual pages) a lone -
is equivalent to --
for this purpose.
Example
You might use:
set -- -a -b file1 file2
to set $1
, $2
, $3
and $4
to -a
, -b
, file1
and file2
respectively. The --
isn't stored - it's just an indicator; without it, the -a
and -b
would be interpreted as possible option for the set
command itself.