I couldn't find anything but is there any reason for choosing % over $ like in *nix shells?
- 23,072
- 4
- 91
- 150
- 3,592
- 1
- 19
- 30
3 Answers
Because it was already reserved for batch file command-line parameters.
Early DOS versions (1.x) did not support environment variables at all. They did, however, support batch files and parameter substitution using the %n syntax (source). The character % was already reserved for that purpose, and already had to be escaped as %% in batch files; it made sense to re-use it for variable substitution, as the two features are quite similar.
The $ character, on the other hand, was already in use in names of temporary files, for example in EDLIN (source; the public source code is from the 2.0 version of DOS, but the binary in the v1.25/bin/ directory contains equivalent code, offset +0xd0 in the binary); subsequent DOS releases added more such uses. If the $ character were used for variables and the user wanted to delete a leftover temporary file with such a name (or, especially, if they wanted to have a batch file do it), the $ character would have to be escaped, which would be inconvenient (not to mention it would pose a slight backwards incompatibility). I am under the impression that Microsoft wanted to avoid adding more escape sequences to COMMAND.COM syntax, from the fact that for example they outright banished <, > and | from file names when pipes were introduced.
Of course, that in turn raises the question why % was used for batch file parameters instead of $, like in the equivalent CP/M functionality provided by the SUBMIT command. Batch files are supported in MS-/PC DOS 1.x, but apparently not in 86-DOS 0.3; the manual makes no mention of it. So it appears the functionality was added sometime between those two versions; this is confirmed by the 86-DOS license agreement between Microsoft and Seattle Computer Products, which (on page 8) mentions “SUBMIT facility comparable to CP/M” as one of the improvements to 86-DOS that Microsoft requested from SCP. We might guess that EDLIN was already using $ for temporary files before batch files were introduced, and indeed, if we disassemble the version of EDLIN found on the even earlier 86-DOS 0.1 floppy image, we find this:
; RBIL #01378, 5Ch:
; first default FCB, filled in from first commandline argument
mov si, 0x5c ; +0x002d be5c00
mov di, 0x5fb ; +0x0030 bffb05
mov cx, 9 ; +0x0033 b90900
rep movsb ; +0x0036 f3a4
mov si, 0x528 ; +0x0038 be2805
movsw ; +0x003b a5
movsb ; +0x003c a4
; INT 21 - DOS 1+ - DELETE FILE USING FCB
mov ah, 0x13 ; +0x003d b413
mov dx, 0x5fb ; +0x003f bafb05
int 0x21 ; +0x0042 cd21
mov al, '$' ; +0x0044 b024
mov di, 0x5fb+9 ; +0x0046 bf0406
stosb ; +0x0049 aa
stosb ; +0x004a aa
stosb ; +0x004b aa
; INT 21 - DOS 1+ - DELETE FILE USING FCB
mov ah, 0x13 ; +0x004c b413
int 0x21 ; +0x004e cd21
; INT 21 - DOS 1+ - CREATE OR TRUNCATE FILE USING FCB
mov ah, 0x16 ; +0x0050 b416
int 0x21 ; +0x0052 cd21
So presumably % was chosen for that reason. But to be sure you’d probably have to ask Tim Paterson; otherwise your guess is as good as mine.
- 23,072
- 4
- 91
- 150
-
Answer can be improved: at some point ^ was added to escape. When was that? – Joshua Dec 12 '21 at 22:29
-
1No earlier than in Windows NT, maybe OS/2. No version of MS-DOS supported it. – user3840170 Dec 12 '21 at 22:41
-
3In many DEC systems, '$' was used as a reserved-to-DEC character in symbol names, as a primitive way to separate the namespace into DEC-use and customer-use. The 'softies would be familiar with this, and I think that's how '$' is used in DOS etc. – dave Dec 17 '22 at 12:27
By using a \ as path separator, they needed a different marker for control character encoding, and did choose $ which in turn meant that the variable marker need to be another one, which turned out as %.
So by choosing % instead they could have kept $ for variables, but then again is the parser structured a bit different as it allows concatenated strings, thus needing a finishing marker at the end of named variables. So they didn't and the rest is history :))
I'm not complete so sure right now about the full implications, but $ is used at least in three different ways on the MS-DOS command line and in batch.
- Expand a batch variable to a full path name with
%~$PATH:<varnumber> - Defining special content for the PROMPT command like date and time as in
prompt $d $t$g. - Code the escape character in parameters as
$elikeecho $e[0mfor screen reset.
Especially the does give the lead here, as marking special characters in Unix is done via a backslash \, which in DOS marks a directory level. MS had to use $ instead, so \e became $e.
Further, but way later (DOS 5)
- DOSKEY used
$to indicate special functions in macro generation.
Surprisingly, its predecessor CP/M did use $ as variable indicator as well as marker for special meanings in some commands (like privileges in STAT).
In CP/M batch files are run with the SUBMIT command, which will read a file (standard ending .SUB) and feed each line to the OS, after replacing variables marked with $. DOS has this feature build in and treats .BAT files like programs.
- 222,541
- 22
- 631
- 918
-
2
-
1CP/M's CCP doesn't give
$any special meaning.STATandSUBMITare transients (separate programs) that interpret command-line parameters or strings in the input themselves. – Blrfl Aug 14 '18 at 13:28 -
4@phuclv Remember that bash is a Johnny-come-lately; that strategy is of a far more ancient lineage. – tchrist Aug 14 '18 at 13:28
-
/was used for options in existing programs so\was most likely chosen to avoid breaking those. – Thorbjørn Ravn Andersen Sep 29 '18 at 23:05 -
2The
%~$PATH:<varnumber>syntax is only supported bycmd.exe, it was never available in DOS. And the bit about ‘control character encoding’ makes no sense. COMMAND.COM has no escape syntax for command lines (other than%%for the%character, and the syntax of thePROMPTvariable). – user3840170 Sep 02 '20 at 08:58 -
1So the use of
-changed the use of/, which changed the use of\, which changed the use of$, which changed the use of%. There's a hole in my bucket, dear Liza, a hole. – DrSheldon Sep 02 '20 at 18:49 -
@DrSheldon: I wonder if there would have been any difficulty using colons as a path specifier (as was done with the later Macintosh), and saying that relative paths are those that either don't contain any colons, or start with either a colon or dot-colon. – supercat Sep 08 '20 at 17:12
-
it certainly gives the impression that they tried to impose their standards with , %, damn drives, CRLF, and failed against Linux/Unix and now we're stuck with both standards... Truly visionnary. Fortunately they didn't invent their flavour of regexes too... – Jean-François Fabre Jan 24 '23 at 19:56
-
1"Impose their standards" seems a bit biased. Why should the designers of system A constrain their choices because of what the designers of system B might have done? Why not complain that Unix did not follow the pre-existing CRLF standard used on DEC systems? – dave Jan 12 '24 at 01:59
I can't know for sure but I suspect one of the reasons was that $ was used as the string terminating character in the standard DOS "print string" API (int 21h ah=9h), a convention apparently inherited from CP/M.
- 121,835
- 17
- 505
- 462
- 1,780
- 11
- 23
%instead of$, but the syntax is different. In *nix, the dollar sign is a sigil, and the percent sign in MS-DOS is more like a magic quotation mark, as variable names must be enclosed in percent signs to be interpolated, rather than just preceded by a percent sign (e. g.%PATH%). This avoids the need to have another magic character, like parentheses to indicate the variable name boundary, like in$(foo)bar. Then it makes sense to use a new character to indicate its new semantics. – Leo B. Aug 14 '18 at 02:07$(foo)means "run commandfooand insert itsstdoutput into the command whereas (in POSIX shell also)${foo}means "value of variable$foo. – wizzwizz4 Aug 14 '18 at 18:48$is a poor choice, especially as$<number>has a special meaning in Unix shells. What if I just want a string containing some number of US dollars? – JeremyP Jan 25 '23 at 10:25