10

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.

1
  • 2
    For what it's worth, POSIX specifications leave set - ... unspecified and only cover set -- .... Beyond that, I don't know what you're asking. The difference is the number of hyphens. The difference in effect (if any) is precisely described in the very document you've quoted. Their differences metaphysically or in general semantics is outside the scope of this site.
    – Wildcard
    Commented Jul 14, 2017 at 22:19

2 Answers 2

13

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
0
9

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .