21

I'm looking for some historical context, valid for both any Windows prompt but my guess would be that the behaviour can be seen at least from MS-DOS, if not earlier.

It feels counter-intuitive to me to have a batch file just ignore the rest of the content if I invoke another bat file without using CALL.

Is there a documented reason why they system was designed this way?

If no documented reason can be found, I'm settling for an educated guess from someone more familiar with DOS than me, which I suspect is most of the people around here :)

Omar and Lorraine
  • 38,883
  • 14
  • 134
  • 274
bracco23
  • 313
  • 2
  • 6
  • 14
    CALL was introduced in MS-DOS 3.3 so before then that was just the way it was. You could use COMMAND /C to run another batch file and return but after returning you would not get back any changes to environment variables etc so of limited use. – Brian Mar 29 '23 at 17:16
  • 18
    'Counter-intuitive' meets 'limited system resources'. – dave Mar 29 '23 at 17:23
  • 1
    The straightforward implementation for batch processing is to just read the input for the command processor from a file instead of the keyboard/stdin/whatever. In this implementation, whenever you start batch processing from a second file, processing the first file obviously stops. To have nested batch processing, you need a call stack. IIRC correctly already CP/M worked this way. (And I don't think this design decision is documented somewhere, the reason is just "we don't have permanent memory to implement a call stack") – dirkt Mar 29 '23 at 17:45
  • 5
    @dirkt No, CP/M could not nest batch execution. At least not the 8 bit variants prior to MS-DOS. The genuine system could only execute a single file with the fixed name $$$.SUB. Which was in turn modified by deleting each line executed - until the file was empty and deleted in total. Very Byzantine. There might have been 3rd party CCP replacements with better batch handling, like ZEX and ZCPR. – Raffzahn Mar 29 '23 at 19:26
  • 6
    @Raffzahn I meant "CP/M already worked by just having the command processor execute a single file, no nesting", not "CP/M already implemented a call stack". Sorry, bad phrasing, and I can't edit it now... – dirkt Mar 30 '23 at 04:02
  • 1
    @dirkt I see. Yeah, not being able to edit comments sometimes sucks. THen again it's important to keep the sequence coherent. – Raffzahn Mar 30 '23 at 12:59
  • The very simple answer is probably "Because QDOS was a CP/M 2.2 clone, which did it this way, and MS-DOS was QDOS made into a product". – Thorbjørn Ravn Andersen Apr 01 '23 at 16:10

1 Answers1

37

It feel counter-intuitive to me to have a batch file just ignore the rest of the content it I invoke another bat file without using call.

Is there a documented reason why they system was designed this way?

Simply resources. Keep in mind, DOS was created to run on machines with less than 64 KiB of RAM (*1), so everything was kept tight (*2).

A Command.com has only provisions for running a single batch file - that is it has only one buffer to hold one file name and a position within(*3). Whenever a command was found to be a batch file, the name entry was replaced by the newly found one and the position counter reset.

To allow nested execution of batch files it would need to maintain a stack of buffers, which would take up much wanted space. Nested execution was introduced with DOS 3.3.

If needed the same could be reached by opening a sub-Shell by executing another Command.com, which would bring its own buffer and thus being able to run another batch file:

COMMAND /C another.bat

When that batch file ended the sub-shell would as well quit and return execution to the previous one. This was also way in line with the idea to develop DOS toward a Unix like environment.

Except the additionally needed resources for the new shell were a quite negative effect. Under PC-DOS 2.0 each level did eat up about 3 KiB:

enter image description here

(Disk statistics removed to reduce size)

Thus DOS 3.3 added a way to execute a nested job by 'calling' it. Introduction of the new CALL keyword was needed to avoid screwing existing batch jobs based on chaining.


*1 - Minimum RAM for DOS 1 is 32 KiB, 48 for DOS 2.x and 64 for DOS 3.x. though, useful operation might need a bit more :))

*2 - In fact, having full batch processing as a build in feature was already a step forward from CP/M where batch files had to be prepared by external SUBMIT command, followed by a system reset after which CCP expected the batch file on the A drive, all of that working somewhat like a AUTOEXEC.BAT :))

Further to allow batch programs to receive user input another program, XSUB had to be started by the batch file. So yes, even the modest features of DOS 1.x batch files were a huge step forward.

*3 - To reserve resources Command even closed a batch file when a program was executed and (re)opened it afterwards, thus freeing an entry in the System File Table (At least since DOS 2.0).

Raffzahn
  • 222,541
  • 22
  • 631
  • 918
  • 1
    Certainly right but note that Unix had shell scripts that nested properly on equally limited resources many years earlier, so the real reason is something along the lines of "poor operating system architecture". – Wolfram Rösler Mar 30 '23 at 12:44
  • 3
    @WolframRösler Unix was nearly useless on a floppy disk based system. Needed a fast disk for swap to make the nesting work without taking all day. – John Doty Mar 30 '23 at 16:35
  • 4
    @WolframRösler Erm, you may want to check again what limited resources means. The minimum requirement for a V5 in 1974 was 40 KiWord (80 KiB) just to boot - and V5 was far from what people today would consider Unix today (14 char filenames). But to compare on the same machine, Xenix-PC (Full V7 of 1984) needed a minimum of 512KiB and a hard disk. Even the single user 1984 PC/IX (SIII) needs 256 KiB and a hard disk as minimum. Neither exactly usable for a PC with a single floppy and <64 KiB RAM. – Raffzahn Mar 30 '23 at 16:38
  • 2
    Using the approach of `COMMAND /C <another.bat> how much of your RAM does that take? I guess I'm asking what the runtime footprint of that was? – davidbak Mar 30 '23 at 17:47
  • 1
    Don't you mean SUBMIT rather than SUBSTITUTE? – John Dallman Mar 30 '23 at 19:09
  • 1
    @JohnDallman Ooops. You're right. – Raffzahn Mar 30 '23 at 19:24
  • 2
    @davidbak Under PC-DOS 2.0 a bit more than 3 KiB per level. – Raffzahn Mar 30 '23 at 19:43
  • 3
    The original UNIX did not have stacking either. A single process was created per terminal and there was no fork, only exec to chain to another program with no return. An exit was identical to exec'ing the shell back into memory fresh. – paxdiablo Mar 30 '23 at 23:16
  • 1
    I remember using *3 back then, when I opened an editor from my batch file in order to edit that exact batch file. The changed file was executed afterwards. (I suppose that happened on a line-position basis, but I don't remember the details.) – Paŭlo Ebermann Mar 31 '23 at 01:06
  • I was going to provide another answer based on the actual source but this answer pretty much nails it. MSDOS 1 had a very simple way of handling batch files. On executing one, it simply set a flag (and set up some params like file handle) and the same loop that handled user input also did line-based batch input by checking that flag to decide where the line should come from. Source available at https://github.com/microsoft/MS-DOS/commit/fce0f75959b9806f4016beb7b19e19b37cc97b6c#diff-5f28f2a58caa6dd7130842541537c71457e3d9bb27a46e60f8d604c255024c3c by the way. Feel free to add link if you wish. – paxdiablo Apr 01 '23 at 04:03
  • XSUB was a resident program that took up extra space. That might be the reason that READLINE did not do this by default. – Thorbjørn Ravn Andersen Apr 01 '23 at 16:13
  • @ThorbjørnRavnAndersen it had to be loaded as first line of a batch, thus being an additional one eating up RAM – Raffzahn Apr 01 '23 at 16:31
  • @Raffzahn Yes, because it was a TSR (but didn¨t have to be the first, just before being needed). The BDOS could have implemented this easily in very little space as the read routines as already there, but for some reason it didn't. – Thorbjørn Ravn Andersen Apr 01 '23 at 16:34