18

I couldn't find anything but is there any reason for choosing % over $ like in *nix shells?

6
  • 3
    Not only MS-DOS uses % 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 2:07
  • 4
    @LeoB. Nitpick: In Bash, $(foo) means "run command foo and insert its stdoutput into the command whereas (in POSIX shell also) ${foo} means "value of variable $foo. – wizzwizz4 Aug 14 '18 at 18:48
  • @wizzwizz4 I was thinking about the Makefile syntax where the parentheses are mandatory. – Leo B. Aug 14 '18 at 19:16
  • 1
    ICL George III also used % but in a completely different way. There were 26 variables and you could do indirection using multiple % signs. The GEORGE equivalent of C's **A would be %%%%%A. – cup Sep 2 '20 at 11:08
  • 1
    One might ask why Unix shells chose "$" when there was already an example of "%" being used for substitution-type operations, in C printf formats. – another-dave Sep 2 '20 at 22:15
11

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 $e like echo $e[0m for 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.

7
  • 2
    In bash they resolve the ambiguities by adding brackets ${var} – phuclv Aug 14 '18 at 0:55
  • CP/M's CCP doesn't give $ any special meaning. STAT and SUBMIT are 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
  • 1
    The %~$PATH:<varnumber> syntax is only supported by cmd.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 the PROMPT variable). – user3840170 Sep 2 '20 at 8:58
  • 1
    So 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 2 '20 at 18:49
10

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 mentions ‘SUBMIT facility comparable to CP/M’ as one of the improvements to 86-DOS that Microsoft requested from SCP. Perhaps % was chosen for reasons similar to the above; per the manual, 86-DOS 0.3 already contained EDLIN, and so we may surmise that $ was already being used as a file name character back then. But to be sure you’d probably have to ask Tim Paterson; otherwise your guess is as good as mine.

2

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.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.