Process substitution was already there in ksh86 and the release notes mention as a difference from the 02/21/85 version is that it was now documented, so presumably it was already there earlier. When it was designed/introduced exactly, we may have to ask David Korn, but it probably doesn't matter, since it probably never got very far out of Bell labs anyway before ksh88.
99% of bash features come either from the Bourne shell, the Korn shell, csh, tcsh or zsh. It's always difficult to find out when and where things were introduced especially when considering that many features of ksh were never documented or documented long after they were introduced.
As far as I can tell, the use of --
as end-of-options-marker starts with sh
and getopt
in System III Unix (1980).
According to this history of the Bourne Shell family, the Bourne Shell first appeared in Version 7 Unix (1979). But it didn't have a way for set
to separate options from arguments. So the original Bourne shell could do:
set -e
- turn on exit-on-error mode
set arg1 arg2 ...
- sets the positional parameters $1=arg1
, $2=arg2
, etc.
But: set arg1 -e arg2
would give you $1=arg1
, $2=arg2
, and turn on exit-on-error. Whoops.
System III Unix (1980) fixed that bug and introduced getopt
. According to getopt
's man page:
NAME
getopt - parse command options
SYNOPSIS
set -- `getopt optstring $∗`
DESCRIPTION
Getopt is used to break up options in command lines for easy parsing by
shell procedures, and to check for legal options. Optstring is a
string of recognized option letters (see getopt(3C)); if a letter is
followed by a colon, the option is expected to have an argument which
may or may not be separated from it by white space. The special option
-- is used to delimit the end of the options. Getopt will place -- in
the arguments at the end of the options, or recognize it if used
explicitly. The shell arguments ($1 $2 . . .) are reset so that each
option is preceded by a - and in its own shell argument; each option
argument is also in its own shell argument.
As far as I can tell, that's the first place it appears.
From there, it seems that other commands adopted the --
convention to resolve argument parsing ambiguities (such as the examples with touch
and rm
you cite above) throughout the wild, standardless days of the 1980s.
Some of these piecemeal adoptions were codified in POSIX.1 (1988), which is where the changelog comment about the "POSIX-required kludge" comes from.
But it wasn't until POSIX.2 (1992) that the Utility Syntax Guidelines were adopted, which contain the famous Guideline 10:
Guideline 10: The argument "--" should be accepted as a delimiter
indicating the end of options. Any following
arguments should be treated as operands, even if they
begin with the '-' character. The "--" argument
should not be used as an option or as an operand.
And that's where it goes from being a "kludge" to a universal recommendation.
Best Answer
Unix was making that distinction since the very beginning, i.e. since version 1 was released in 1971.
The system was booting to multi-user mode (i.e. users connected to the available serial interfaces,
tty0
totty5
but provision was made to add four more ttys).Unix v1 manual states for the section 4,
tty
page:Note that with this first Unix release, spawning the login processes to each serial line was hardcoded and done by the init process itself. Selecting which mode to use was done before booting and switching to multi-user mode was done by modifying the switch settings and exiting the single user mode shell.
Later, with Unix Version 7 (1979), instead of hardware switches, the system was booting first in single user mode and when the single user shell exited, it switched to multi-user mode.
Even later, System III (1981) introduced the
inittab
file. With it, it was possible to better define and configure multiple run levels and select the one to use. Run level 1 was single-user and run level 2 multi-user. If the inittab file was missing, the system booted in single-user mode.