9. DOS (Batch) Primer

This section describes how to use the DOS prompt and how to write DOS batch files.

Although you could use ADB entirely as a called executable within another larger compiled program, both programmers and non-programmers will probably find the DOS batch interface more flexible and convenient.

Unix users will have to get used to the fact that DOS "scripts" are very limited by comparison to either C or Bourne shell scripts.

I don't presume that you have any existing knowledge about the DOS command line and batch file interface.

Feel free to mail your comments to me at: rog@NOSPAM_rs-freeware.org.

Return to the global table of contents
Frames mode, or No frames


1:  What to do if you're only interested in my DOS primer, and you don't care about ADB

2:  Introductory digression: Why DOS?

3:  Before You Begin

4:  DOS Shell, Environment, Variables, and Long File Names

5:  More on file names: Drives, paths, folders, and extensions

6:  The DOS PATH variable (and executable file name extensions)

7:  "Built in" commands versus executable programs

8:  Making DOS Executables Assessible Via your PATH

9:  Making DOS your "home away from the desktop"

10:  Standard input, standard output, and pipes

11:  Appending files with ">>"

12:  The NT redirection bug

13:  The basic DOS commands

14:  DOS Batch Files: Essentials

15:  DOS Batch Files: Advanced

16:  DOS Batch Files: Esoterica

17:  Other sections that you should read, even if you're only interested in DOS, and don't care about ADB


1:  What to do if you're only interested in my DOS primer, and you don't care about ADB

You still need to download ADB.Zip, and unzip it in a new folder.

This will ensure that you have all the files you need to take advantage of the DOS primer, and utilities discussions.  For more information about what ADB.Zip contains, see the list of files.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

2:  Introductory digression: Why DOS?

(You can skip this part if you want.  This just consists of some personal comments about the DOS batch interface.)

If you're a Unix programmer, you probably recognize the inherent flexibility and virtues of creating complexity out of simplicity, but you may also realize that WinTel OSs are inherently inefficient by comparison to Unix.

While that's clearly the case, WinTel is here to stay, and DOS/WIntel applications have a tremendous amount of portability . . . both as standalone batch processes, as well as "daemons" that run on servers that process data collected by CGI programs.

The DOS WinTel interface is also relatively stable over time (and compatible across machines).  In fact, my experience with Unix suggests that it's much more difficult to write portable Unix applications--even the differences between Ultrix (SGI) and Sun can be quite trying.  (But don't get me wrong--DOS is a tricycle by comparison to Unix's 10-speed bicycle.)

The main purpose of this section is to show novices, managers, traditional DOS programmers, and Unix afficiandos how to get the most out of the DOS batch interface.

If you're a Unix person, most of the concepts will be familiar, albeit on a much larger scale.  (You may also find yourself tempted to scream from time to time because DOS is so restrictive by comparison.)

If you're a WinTel programmer, you might be surprised at how much can be done from the DOS command line.  No doubt you'll be disappointed at the absence of an ability to create a GUI user interface.  But that's not what this is about.  My goal here is to show you how you can push around data in a batch environment.

It goes without saying (but I'll say it anyway) that virtually all modern WinTel programming languages have interfaces that allow you to invoke the DOS command processor to get things done in the background.  You may find that using the DOS command line environment (along with some of the tools described in the next section) vastly reduces the amount of code that you have to write debug, and maintain for your applications that have GUI interfaces.

Again: this is particularly true for server-side applications that need to collect and store data on NT servers.  Batch files and simple compiled executables can work just as well as many other methods for maintaining databases (for many applications).

If you're not a programmer, you'll (hopefully) be amazed at how much power the DOS command line gives to you when it comes to writing simple, yet powerful processes.

And finally: if you're a manager, you may find that many of your programmers can achieve a higher rate of productivity by learning to drive a "stick shift" instead of an "automatic."

But no matter who you are, "your mileage may vary."

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

3:  Before You Begin

Please accomplish the following tasks, in order, before you read the rest of this section.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

4:  DOS Shell, Environment, Variables, and Long File Names

The DOS "shell" is the program that's responsible for taking your command line input (or batch files) and executing it.  It also handles various other system "calls."

The program is called "Command.Com" and it's normally in your C:\Windows folder (this is different for NT, I believe).  It's also on your root folder of your C drive.

I'll talk more about how you can (and should) actually call this program, via the standard variable %COMSPEC%.

The DOS environment is simply a "set" of variable/value pairs. If you go to the DOS prompt and type "Set" (don't forget to hit enter after that), you'll see your DOS environment.  Each variable is listed on the left, followed by an equals sign, and the variable's value.

If the results scroll off the screen, try this:


Set | More


The DOS environment has a maximum size.  I.e. a maximum number of bytes that are available to hold the names of variables and their values.  In the first section above, I showed you how to make sure that the DOS environment size was set to 4K.  This prevents you from accidentally exceeding it (if you do, DOS won't let you assign any more variables.)


You can set any DOS variable at the command line, like so:


Set MY_VARNAME=my value

This sets the variable: MY_VARNAME

To the value: my value


DOS variable names can use digits, dashes, underscores, and letters (they can even begin with digits, although I personally think that's bad style).

You may be able to use other special characters as well.  You can't have an embedded space.  DOS variable names are case sensitive.


One of the big problems associated with DOS variables is that you can't set them to values that contain the equals sign or the greater-than/less-than signs.  You also can't assign them to values that have trailing spaces, or any unprintable characters (anything below a space).

To assign a DOS variable to a value that contains a percent sign, use two percent signs in a row.


To clear a DOS variable, simply assign it to nothing.  E.g.:


Set MY_VARNAME=

You can verify that it's been cleared by typing Set (or "Set | More" at the command prompt.

Note that it's impossible to assign a DOS variable to nothing (or spaces).  Essentially, there's no "null" value (other than "unassigned").  One of the very annoying things about DOS is that an unassigned variable "evaluates" to nothing (the empty string).

That means that if you mistype a variable name in a DOS batch file, DOS will silently replace it with nothing (i.e. you'll get no warning or error messages.)


You can only use a DOS variable's value within a DOS batch file.  That is to say, you can't use the value for any purpose at the command line.


When accessing the value of a DOS variable, you enclose it in percent signs.

For example, this DOS batch file will list the contents of the folder C:\Windows:


Set FOL=C:\Windows
Dir %FOL%

(The DOS "dir" command lists all the files in a folder, or just a single file.)

Suppose you were to leave the percent signs off?


Set FOL=C:\Windows
Dir FOL

In that case, DOS would think that you wanted to list the folder named "FOL", not the folder named C:\Windows.

Although JavaScript and VBS are exceptions because they use quote characters to distinguish constants from variables, many scripting languages (such as C shell and Bourne shell scripts) do have this requirement.  I.e.: you set a variable value without any special characters, but if you're going to use a variable's value, then you must add special characters to let the system know that it's a variable instead of a constant.


What happens if you code a batch file that looks like this?


Set FOL=C:\My Documents
Dir %FOL%

Unfortunately the Dir command expects one argument to be the file name (and spaces are used to separate arguments.)

The way around this is to wrap it in double quotes.  The DOS command line has special support for these:


Set FOL="C:\My Documents"
Dir %FOL%

You can also do this:


Set FOL=C:\My Documents
Dir "%FOL%"

DOS variables' values are replaced within double quotes.  And even if FOL was set to a folder name that didn't have embedded spaces, the batch file would still work just fine.


You can concatenate (merge) DOS variables with other variables or strings by running them together.  E.g.:


Set DRIVE=C:
Set FOL=\Windows
Dir "%DRIVE%%FOL%"

This lists the contents of C:\Windows.  (It won't work from the DOS command line, because you can't refer to variables' values that way.  You have to put it in a batch file.

To see this example in action, save it as "C:\Windows\Temp.Bat" and then enter the same thing at the DOS command line. Just as this does:


Set FOL=\Windows
Dir "C:%FOL%"

Or this:


Set FOL=Windows
Dir "C:\%FOL%"


Note that DOS file names are case INsensitive.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

5:  More on file names: Drives, paths, folders, and extensions

A "fully specified" DOS file name looks something like this:


C:\Windows\DeskTop\Etc\ICQ.Lnk

This is the folder on my Windows desktop which I use to organize the space.  It has a number of "shortcut" icons in it.)

(If you're a longtime Windows user, you probably have at least one folder on your desktop that has a similar function, i.e. something that organizes your desktop icons.)

The term "path" applies to the part of the file name before the last backslash.  The path for this file is:


C:\Windows\DeskTop\Etc

The "base file name" in DOS is just the rest of the file name. That's: "ICQ.Lnk".

(Unix users beware: the Unix "basename" command returns the part of the file name before the last dot, excluding path information.)

The part after the dot is the filename "extension".

In DOS and/or Windows (as well as Unix) file name extensions are used to convey the purpose and nature of the file.  E.g.: ".txt", ".pl", ".html", etc.)

For this file name ("C:\Windows\DeskTop\Etc\ICQ.Lnk"), the extension is "Lnk".  (Sometimes people use a dot at the beginning of file extension, just to emphasize that it's the part after the dot.)

Like Unix, DOS has two "wildcard" characters, which are used to refer to many files at once.


Many of the standard DOS commands will take wildcards.

The "*" (asterisk) can be placed anywhere in a file name, but is generally used instead of the first part.  E.g.:


Dir *.Txt

This lists all the *.Txt files in the current folder, also known as the default directory.


What's the "current folder"?

When you're at the DOS prompt, you'll see it on the right.  The default is usually either "C:\Windows" or "C:\My Documents".  Note that you can change the default directory by using Windows to change the properties of the DOS prompt.  You can also specify a batch file to be run whenever you go into the DOS prompt.

The "?" can be placed anywhere in a file name.  Unlike Unix, the DOS "?" must stand for at least one character.  For example, listing all files in the folder with the wildcard filename:


Dir Temp?.Txt

does not include "temp.txt" in DOS (because the "?" is being replaced with zero characters, instead of 1).   But it does include "Temp1.Txt" and other files whose base names have exactly one character between "Temp" and ".Txt".

Unix users beware: DOS filenames are case INsensitive.


You can change the current folder with the CD command.  (CD is short for "change directory", because "folders" used to be called "directories" before Windows, and still are in Unix).

For example if the DOS prompt says C:\Windows, and you want to be in C:\Windows\System, simply execute this command at the DOS prompt:


CD System


If the DOS prompt now tells you that you're in C:\Windows\System, and you want to get back to C:\Windows\Commands, you can say:


CD ..\Commands

The ".." here refers to the enclosing folder (directory).  Think of ".." as being literally replaced with the enclosing folder name.

In other words, if you're in C:\Windows\System, then these two commands will take you to C:\Windows\Command:


CD ..\Commands
CD C:\Windows\Commands
(In this case, ".." was replaced by C:\Windows.)

Alternatively you can use ".." by itself.  So if you start out in C:\Windows\System and enter:


CD ..

then you'll be in C:\Windows


DOS has a special syntax for the current folder.  It's a single dot. For example:


CD .\System
and


CD System

are the same thing.  Because the dot in the first one is replaced with the current folder name.

This may not seem like a very useful syntax, but it's particularly helpful when a command requires a path name.  For example, if you are in the folder C:\Windows and you want to copy C:\AutoExec.Bat to this folder, you can type:


Copy \AutoExec.Bat .

Note that I didn't even need a drive name, because the C: drive is the default.  The backslash in front of "AutoExec.Bat" says that the file is in the "root folder" (the top level folder of the default drive, i.e. C:).

You might find it confusing that Windows lets you create file names with lots of periods.  E.g.:

This is the letter that I wrote to my friend.  Last Summer.txt

(IMO it was a regrettable decision by MS to allow periods before the extension).

In any event, the extension is whatever's after the last period.


Finally, you may wonder how to change the default hard drive (if your computer has more than one).  Simply enter the drive name with a colon after it.

E.g.:


D:

Assuming that you have a drive named "D", this command will change the default drive to D.  Note that DOS will "remember" the default folder on a drive when you move back and forth between drives.

If you don't know how many drives your computer has (and what types of drives they are), you can click on Windows' My Computer icon.  Each drive there is labelled with its letter and a colon following it.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

6:  The DOS PATH variable (and executable file name extensions)

(Unix users will already be familiar with the concept of the PATH, but should read this section anyway.

Go to the DOS prompt and type:


Set | More

This will list all the variables in your DOS environment.

One of these variables will be called PATH.  On my machine, it looks like this:


PATH=D:\PROGRAMS\WINSYNCH;C:\WINDOWS;
C:\WINDOWS\COMMAND;D:\UTIL;
D:\TC;D:\SYS;D:\PCTEX

(This is just one long line, that I've split into three for ease of display for readers who may desire large font sizes on their browsers).

The DOS path consists of a list of folder names, separated by semicolons.


Whenever you type a DOS command, DOS checks for two things.

First, if the command is a "built in" DOS command (such as the "Dir" command), then DOS will execute that command.

Next, it checks for the command in the current folder.  If it doesn't find it there, it will search the folders listed in the DOS PATH.

If it doesn't find the file in any of the folders, it will print the DOS user's favorite message:

Bad command or file name


Not every file can be "executed" (i.e. not every file is viewed by DOS as a "runnable program.").

Unlike Unix, DOS knows whether a file can be executed (and the type of executable file) by the extension.  DOS has no "executable" file attribute bit (or "mode" bit, to use Unix terminology).

Most executable (AKA runnable) files end in an extension of "Exe". In fact, "Exe" is short for "executable."

DOS "batch" files are basically ASC text files that are full of commands.  Any command that you enter at the DOS prompt can go in a DOS batch file.

However, not every command that can go in a DOS batch file can be entered at the command prompt.  For example, you can't use the value of a DOS variable at the command prompt (Unix does permit this).

Every DOS batch file must end in an extension of "Bat".  DOS batch files must be "ASC text files", i.e. the sorts of files that you can edit with Windows Notepad.

Finally, files which end in "Com" are also executable.  Com files are very special types of executable files with no analogy that I know of in Unix.

Like executable files, "Com" files also consist of what's known as "object code" (if that phrase makes no sense to you, please ignore this sentence.)

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

7:  "Built in" commands versus executable programs

(Unix users can skip this part.)

If you're a curious person, you may have fired up the "find" facility from your Start menu in order to search for some of the DOS functions that we've been using.

Specifically, I just told you that DOS executables have one of 3 possible extensions: "Com", "Exe" or "Bat".

So-o, it would make sense that there's a program called "cd.exe" or "cd.com" someplace on your hard drive, right? (For the "CD" command.)

However, there isn't.  A certain number of DOS commands are "built in" to the DOS shell program.

No matter how the DOS PATH is set, the "built in" DOS commands will always work.

It's not essential that you be aware of the distinction, but if you ever get onto an unfamiliar machine, it's good to know that CD, Copy, Dir, Del, Echo, Set and Type (we'll cover that later) will always work.

The same goes for the special colon syntax that you use to change the default hard drive.  E.g. you can type:


D:

to change to drive D.  (Presuming that your computer has such a drive.)

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

8:  Making DOS Executables Assessible Via your PATH

In the installation, I tell you to unzip the install Zips in a special folder that you've created for ADB.

To make sure you can execute them, modify the "Set PATH=" line in C:\AutoExec.Bat to include this extra folder.  You can add it in as the last folder in the list.

You need to reboot to make the changes in AutoExec.Bat effective.

It's worth mentioning here that there are two strategies that you can use when installing DOS systems' executable files.

One approach is to create a new folder for each system, and include that file in your DOS path.

Another is to create a special folder for all such systems.  For example, on my hard drive, I have a folder called "UTIL".  It's listed in my DOS PATH.

Whenever I install a new DOS system, I simply copy all the *.Exe, *.Com, and *.Bat files to my UTIL folder.

Although this approach is "neater", there is always a small chance that you'll overwrite an existing file in the UTIL folder (or whatever name you give it).  So it's always a good idea to check to see whether there are any name duplicates.  In a well-designed DOS system, each program should have a name that's likely to be unique, so there's little chance of that.


[Irrelevant digression:]

If you're a committed Windows user, this whole business of using the DOS PATH may seem like a great annoyance to you.

After all, Windows (except 3.1) has the "registry," in which Windows stores all relevant information for all applications.

Needless to say, the registy has its own problems: it makes it difficult to move applications between physical hard drives (or install a new hard drive), it's easily corrupted, and difficult to restore (unless a backup copy is available).

Personally, I vastly prefer the control that DOS systems provide me (not to mention their much greater portability).  I also find it very annoying to have to search through registry keys to make the most trivial changes to WIndows applications (e.g.: what folder will Notepad and Wordpad open up by default?).  This goes back to the idea that Microsoft doesn't want you to control your computer; instead they want to control you through your computer.  Personally, I'd rather be confused than controlled.
[End digression]

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

9:  Making DOS your "home away from the desktop"

If you're a Unix user, you already recognize the value of having a "command line".

If not, let me ask you to consider the following analogy.

Suppose you like a particular national/regional style of cooking. Ethiopian, Indian, Italian . . . Korean, Mexican, American Southern, . . .  pick your favorite(s).

Now: would you rather live in an area where there are many fine restaurants of this sort, or would you rather learn how to buy the ingredients, maintain a well-stocked pantry, and have a kitchen that was well-equipped to make the recipies involved?

Obviously the answer to the question depends on a lot of variables.

But there's no question that you'll be able to enjoy the most satisfying culinary pleasures if you learn the art of cusine, as understood by the various cultural models that you wish to partake.

Becoming "at home" with the DOS command line is rather like bringing a different kind of cuisine to your kitchen.  There are quite a few new tools that you need to aquire, especially if you're a committed Windows GUI interface user.

You may feel that too much time and energy is needed to make these adjustments.

It's really up to you.

I've included the basics that you need in the ADB_Etc.Zip install file:

  • TurboKey.Com: The keyboard "whizzer"

    TurboKey's a great freeware keyboard acellerator, far beyond anything offered by MS.

    Evidently Misrosoft just doesn't think your arrow keys should move the cursor too quickly.  <sigh>

  • A DOS command line editor.

    A good DOS command line editor should allow you to use the arrow keys to "recall" previous entries that you've done at the DOS command line, and to "edit" (i.e. change) them.  DOSEdit is a fair command line editor.

    I've also included my personal favorite, Anarkey.Com, with the main distribution package.  Anarkey is shareware, so you will need to spend $30 to buy it.  IMO, it's well worth the price.

    If you don't wish to use Anarkey, the DOSKey program that comes with Windows 9x may be a suitable replacement.

  • A DOS editor, with mutliple windows support, a file manager, a DOS command prompt ("shelling") and binary file support.

    If you've never "flipped" back-and-forth between mutliple windows in a DOS editor, nor scrolled through a 2,000 line file in just a fraction of a second, you have no idea how fast, easy, and supple "text only" interfaces truly are (by comparison to GUI).

    While my favorite DOS editor is Boreland's SideKick Plus, this is no longer available to the public.  (You may still be able to get the successor, called SideKick II.  I find it much more difficult to use, due to the dearth of configuration options.)

    The closest approximation that I've been able to find is a nifty $35 piece of shareware called "Breeze" (in Breeze56.Zip).

    Although Breeze (for reasons unknown to me) clobbers TurboKey's keyboard speed enhancements, it does allow you to invoke the DOS shell, and it lets you edit binary files and set the display colors.  I think it's a fine piece of work.

    I've also supplied a piece of freeware called DEdit (in DEdt0942.Zip).  DEdit is Windows-based, and will run from your desktop.  It doesn't have as many nice features as Breeze, but it will handle 32-bit FATs (file allocation tables).

    Whatever editor you choose, make sure that line and column numbers are shown.  This is perhaps the main reason why Windows Notepad isn't a suitable choice (Notepad also defaults to using "word wrapping," which is a read pain in the neck if you want to write code.)

    If you don't want to install Breeze or a similar editor, then DOS EDIT is a suitable compromise.  At least it provides you with multiple windows, a fixed-size font, and line/column numbers (but no DOS shell, and no binary files capability and IMO these are crucial defects.)

Finally, you should know how to customize the DOS prompt and create shortcuts on your desktop.  I'm not going to explain how to do this.

If you have a large monitor (say: 17" or more), you may wish to run the DOS command line on your windows desktop (instead of in full screen mode).  Unless your computer is very fast (i.e., 700MZ or more), you may find that the GUI interface slows you down considerably.  Nevertheless, this will allow you to have multiple-window editing as well as the command line on your desktop--all at once.

Make sure you use a "fixed space" rather than a proportional font in your DOS window(s).  You might also consider upgrading your computer's fonts at: http://www.microsoft.com/truetype

(It's crucial for you to have a highly readable font with "fixed" spacing.)


Suffice to say that you can have multiple DOS icons on your desktop for a variety of purposes.  You can also create them for your users, in order to make it easier for them to run multiple processes.

(The DOS icon is relatively unique in this one regard: every time you create a "shortcut", you can right-click on that shortcut to change the icon's properties.)


If none of the products in the list above seem suitable, I recommend that you go to:

http://oak.oakland.edu/

Once there, look for the "Simtel" DOS archives.  These are archives of freeware and shareware which have been maintained for some decades by the U.S. Government in coooperation with Oakland University and other pubilc-spirited organizations.

Most of the software there is excellent.


For another fabulous source of free software, consider FSF (AKA "Free Software Foundation"--the "GNU" folks): http://www.gnu.org/software/

In fact, if your budget isn't too limited, I'd recommend that you order the CD-ROM entitled "GNU Software for MS Windows and MS DOS" at: http://www.gnu.org/order/order.html

(Note: the above URL will take you to the main ordering page for GNU.  As of this writing, the following one will take you directly to the CD-ROM that I just mentioned: http://www.gnu.org/order/windows.html

This is an incredbly useful tool for consultants, because GNU software can be distributed with your packages; it's also excellent for organizations, because you don't need a license for each machine on which it runs.  In fact, you can get the very same software via FTP, but having the CD is an excellent way to save time.

Unix users should note that the CD-ROM contains GNU's own version of BASH (the "Born-again Bourne Shell").

If you work for a corporation, I'd like to make a personal plea to you: spend the $140 for the corporate CD.  The folks at GNU are making the world a better place to live.  Kindly help them out.


[Irrelevant digression]

IMO, most of the DOS stuff available at Simtel and GNU is top-quality.  It was written many years ago, when computational resource were tight, users were highly sophisticated, and the U.S. and European economies weren't doing so well.  The programmers who wrote these packages had a committment to producing excellent and inexpensive software (complete with useful documentation).

Few if any of these packages will "tell you what to do" when you run them.  As a general matter, the best DOS software is built with a user who "thinks for him/herself" in mind.

At the same time, the writers of this code sought to provide more than mere Unix-style "man" entries.

In particular, they didn't wish to see their users as engaged in a "one upmanship" contest when it came to the knowlege of obscure facts.  So they wrote excellent documentation, complete with examples and the kind of discussion which allowed you (as a user) to "see inside" the product, and to have a remarkable amount of configuration power.

If you're a Unix user, you may find the level of disclosure and discussion to be strange, unfamiliar, and perhaps a tad on the "wimpy" side.

And if you're a modern GUI user, you may find yourself annoyed with the lengthy and detailed nature of the documentation. Trust me.  If you "RTFM" (read the "fine" manual), you'll spend a lot less time wondering what to do . . . and save yourself a ton of frustration as well as wasted time in the end.  You can get a lot more done with software that presumes you have a working brain (as well as the inclination to use it.)

Personally, I believe that the "golden decade" of DOS software (1982-92) produced some of the finest products I've encountered in a quarter century of programming.  If you like, you can view this product to be a kind of homage to the excellent shareware produced in the late 80s and early 90s.  And to be complete in my remarks: the folks at the Free Software Foundation have never lost this splendid esprit de corps.

And while I'm comfortable with most aspects of the Windows GUI interface, my personal productivity as a programmer and technical person has always been highest with command-line software (whether DOS or Unix), at least in part because I can write "batch" operations (scripts in Unix) to eliminate tedious and repetitive tasks.

But as always: "Your mileage may vary."
[End digression]

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

10:  Standard input, standard output, and pipes

(If you're a Unix user, you can skip this section.  Just remember that DOS doesn't have the Unix ">2" and ">>2" constructs.  There's no way to redirect standard error, nor can you redirect the output of a DOS batch file in the same way as you can with a Unix script. And in general, you can't replicate "file descriptors" or access them by number, as with Unix.  As I've said many times, DOS is much more limited--but not entirely useless.)

Many DOS commands and DOS programs read their input files from the "standard input".  What does the term _really_ mean?

I can't give you a simple definition, but in practical terms, maybe the best way to think of the "standard input" is that it's the "default" input file for an operation.  (C/C++ programmers will the standard input as the stream FILE called "stdin", and standard output as the stream FILE called "stdout").

As a simple example, suppose the file "Unsorted.Txt" consists of people's names (last name first) and the cities and states in which they reside.

I've included a "column ruler" at the top for easy reference:


123456789012345678901234567890
Lopez Rosa  Chicago    IL
Berry Derek Washington DC
Blow  Joe   Pasedena   CA

We can use the DOS sort command to sort the file by state (the state field starts at column 24, as the ruler indicates):


Sort /+24 < Unsorted.Txt

The output will be:


Blow  Joe   Pasedena   CA
Berry Derek Washington DC
Lopez Rosa  Chicago    IL

The less-than sign in front of Unsorted.Txt specifies that the "standard input" is the file Unsorted.Txt.

If we wanted to output the sorted file into Sorted.Txt, we'd code a command line like this:


Sort /+24 < Unsorted.Txt> Sorted.Txt

The greater-than sign specifies that the "standard output" is to be sent to Sorted.Txt.  If you hadn't specified a standard output file, then DOS would've sent this value to the "console" (i.e. your DOS window).

Note that if you don't supply a "standard input", then a blank line will appear on your screen.  The default standard input is always the "console."  If you wish to use this option, you can tell DOS that you have no more lines to enter by typing a control-Z.


Whenever you do specify a file name for standard input or standard output, this is known as redirection.


DOS also allows you to "chain" commands' standard inputs and standard output's together.

For example, suppose you want to sort a directory listing.

If you type:


Dir *.Txt

at the DOS command line, this will list all the *.Txt files in the current folder.


You could sort this listing by redirecting the standard output to a file:


Dir *.Txt> Temp.Dat

Then you could sort the file:


Sort < Temp.Dat

DOS allows you to do this in one step, without a temporary file.


Dir *.Txt | Sort

The bar ("|") specifies that the standard output of the previous command is to become the standard input for the next one.

When the bar is used in this way, it's known as a "pipe" (for reasons that must be rather obvious).

Try the following.

Get into the C:\Windows folder.  There are a lot of *.Exe (executable) files there.

If you've forgotten how to "get into" a folder at the DOS prompt, let me remind you that the two steps are:


C:
CD \Windows

The first step will make sure that the default drive is C.  If you only have one hard disk on your computer, that's not necessary.  The second will make C:\Windows into the default folder.

Now try this:


Dir *.Exe

This lists all *.Exe files in the folder.

As you may have noticed, the list is too large for one DOS window.

In fact, if you're using DOS in full screen mode, it's almost certainly "scrolled off your screen."

Let's see if we can use some of our fledgling DOS skills to find a solution for this. First, try this:


Dir *.Exe> Temp.Dat

This "redirects" the standard input into the file Temp.Dat.

Next, let's see if we can look at the file.  One of the simplist ways to do this from the DOS prompt is just to use More:


More < Temp.Dat

In this case, we've "redirected" the standard input of more.

Now let's combine the two with the pipe:


Dir *.Exe | More


Although no treatment of DOS and DOS batch files would be complete without a discussion of pipes, it's worth mentioning that pipes make it difficult to check for the "return codes" of the programs that you're running.  (Unix users: note that DOS has nothing parallel to the Unix shells' "||" and "&&" chaining commands.)

I'll have more to say about what a "return code" is later on, but for now, just remember that it tells you whether a program failed or succeeded.

(More precisely, it can tell you whether a program failed or succeeded, depending on whether the author of the program decided worry about "setting" the return code.  Nevertheless, most serious programmers do set the code, and it's the most important mechanism available for writing "bulletproofed" DOS batch files which have the power to make irrovocable changes in "production data.")

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

11:  Appending files with ">>"

(Unix users can skip this section.)

You can also "redirect" the standard output of a command to a file and append the results to an existing file.

For example, this batch file will collect the names of all *.Txt and *.Xls files in the file called "Temp.Lst":


Dir *.Txt> Temp.Lst
Dir *.Xls>> Temp.Lst

The first command invokes the DOS command to list the contents of a directory, and redirects the output to Temp.Lst.

If Temp.Lst already exists, it's replaced with the redirected output of the Dir command.

The second command appends the output of the directory listing to Temp.Lst.

I.e. all lines in the listing of Excel (*.Xls) files are added to the end of Temp.Lst.

The ">>" redirection command is the main reason why the DOS Type command is useful.

To append the contents of file A.Dat to file B.Dat, just use this command:


Type A.Dat>> B.Dat

">>" is also very useful with DOS Echo, if you want to write a fixed string to a file.  (If you're not a programmer, the term "string" may appear unfamiliar.  A _string_ is just a value which is text, as opposed to numeric.)

E.g.:

Echo This is a Test>> Test.Dat

Now the last line of Test.Dat is:


This is a test

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

12:  The NT redirection bug

If you want your DOS batch files to be truly portable (or if you use Windows NT), you'll need to be careful about the NT redirection bug.

NT will not handle a DOS variable which occurs immediately after a > or < sign.  For that reason, you should always put a space afterwards.

For good measure, I also try to put a space before and after a < sign and one space around the "bar" (AKA "pipe") character: |

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

13:  The basic DOS commands

I'm not going to explain how to run each of these commands.  Instead, at the end of this subsection, I'll give you a DOS batch file that prints out the help screens for each of these commands.  I also analyze the file (this is the first "real" example DOS batch file that we'll see).

If you ever need help on a DOS command, you can always enter the ~name of the command followed by "/?".

For example, if you enter this at the DOS prompt:


Dir /?

you'll learn how to use the extremely useful DOS dir command, which lists all the files in a folder (or in multiple folders).

If you're a committed Windows user, you may wonder why you should bother, when you can use Windows Explorer.

The same goes for commands such as Move.  (You can, after all, just drag and drop the file from one folder to another.)

For one thing, I think you'll find that the DOS command line is actually faster than the GUI interface--presuming that you can "touch type" or are fast "hunt-n'-peck" typist.

Even if you're not a fast typist, you absolutely must know most DOS commands if you're going to be able to write DOS batch files.

However, there are a few exceptions.  These commands are mainly used at the DOS command line, and you can substitute GUI-based Windows operations for them if you like:


    Find     -- Searches files for a text string
    FC       -- Compares two files to see if there are any
                 differences
    More     -- Displays a file, one screen at a time

But these commands are absolutely crucial for DOS batch files (as well as being useful at the command line):


    CD       -- Changes the default directory.
    Copy     -- Copies files (note the "/b" operand, required
                 for binary files.)
    Choice   -- Similar to ADB's utility called BE2.
                 I'll discuss this in the next section.
                 (Note: Choice only exists in Windows 9x.  Use my utility
                  BE2 for other versions of Windows)
    Del      -- Deletes file(s)
    DelTree  -- Deletes all files in a folder and all
                 enclosed folders.
    Dir      -- Lists one or more DOS directories
    Echo     -- Takes its arguments and writes to the s
                 standard output. (Echo is very useful for
                 building files--see the next section).
    Move     -- Moves a file
    Type     -- Types a file to standard output, very useful
                 for concatenating (merging) files, as in:
                 Type FileA.Dat >> FileB.Dat
                 (FileB.Dat just had the contents of FileA.Dat
                 added to the end of it.)
    Pause    -- Prints the line:
                 Press any key to continue . . .
                 and waits for the user to press a key.
                 This is replaced by ADB's utility ErrMsg.
    Rem      -- Useful for making remarks in a DOS batch file.
    Set      -- Sets a DOS variable to a value, or display all
                 variable settings (if run by itself).
                 Use "Set Variable=" (where "Variable" is the
                 variable name) to get rid of a variable,
                 i.e. clear it.
    Sort     -- This is DOS's standard sort, which is much
                 less useful than RPSort.Com (an ADB
                 subprocesses).
    XCopy    -- Similar to Copy but less useful because
                 there's no way to suppress its inquiry
                 prompts.  However XCopy can also
                 copy an entire directory structure.


Three of these commands behave specially with folder names and/or wildcards.

Let's start with Copy.


Copy folder_name

This command will copy all the files in folder_name into the current folder.  In particular, folder_name will become a subfolder of the current folder.  If folder_name has folders within it, these folders will not be copied.

Note that the default second file name for Copy is always the same as the first file (or folder) name.

So if you say:


Copy \AutoExec.bat

then the file AutoExec.Bat will be copied into the current folder.

This is the same as saying:


Copy \Autoexec.Bat *.*

Or:


Copy \AutoExec.Bat .\*.*

(Note that the dot before the backslash refers to the current folder.)


If you want to use XCopy to copy a folder name (and all subfolders, as well as all files in all subfolders) to another folder, you should use it like this:


XCopy /s \Windows\*.* \Windows2\*.*

This will completely replicate the entire Windows folder to a new folder, called "Windows2".  Note the "/s" (subfolders) option.

Move will also behave in a highly specialized manner with folder names and/or wildcards.


To move an entire folder structure:


Move \Windows \Windows2

(BTW: I recommend that you refrain from actually executing this example!)

Move is also useful for moving a bunch of files at once:


Move C:\Windows\*.Exe .

(That will move all *.Exe files in C:\Windows to the current folder. Again, I recommend that you do not actually use that example.)


Copy has a special ability to concatenate (merge) files.  For example,


Copy *.Txt Temp.Dat

will copy all files of the form *.Txt to the file Temp.Dat.

Note that the Copy command will copy the input files in "DOS order". I.e., in the order that they're listed with the DOS "dir" command.

As it turns out, this is the order in which they're entered into the so-called "FAT" (file allocation table).  This sequence is essentially arbitrary.


You can also use Copy to concatenate (merge) files like so:


Copy Temp1.Txt+Temp2.Txt+Temp3.Txt Temp.Txt

This merges the files Temp1.Txt . . . Temp3.Txt (in that specific sequence) to the file Temp.Txt.  If Temp.Txt exists, it will be overwritten (i.e.: replaced).


In the next subsection, I'll begin explaining how to write DOS batch files.

But for now, it's time to write our first one.

This file will do nothing more than accumulate the "help" pages for each DOS command.


If Exist Temp.Dat Del Temp.Dat
If Exist Temp.Txt Del Temp.Txt
Echo                                         *>> Temp.Dat
Echo ****************************************>> Temp.Dat
Echo                                         *>> Temp.Dat
CD         /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
@Rem Remove the next line for Windows NT, 2K, or XP
Choice     /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Copy       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Del        /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
DelTree    /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Dir        /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Echo       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
FC         /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Find       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
More       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Move       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Pause      /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Rem        /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Set        /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Sort       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
Type       /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt
XCopy      /?>> Temp.Txt
Type Temp.Dat>> Temp.Txt

After running this file, the file "Temp.Txt" should be a handy guide that you can use when running the DOS commands.  That, in conjunction with the information in this section, should put you well on the road to writing your own DOS batch files.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

14:  DOS Batch Files: Essentials

(Unix users may find this section annoying because they already understand the concepts, but the specific manner in which they translate to DOS is important.)

The first thing to remember about writing DOS batch files is you're structuring a process with two kinds of building blocks:

This duality is common to all forms of "scripting" and should be quite familiar to those of you who've worked with Unix.


I briefly spoke about "return codes" in an earlier section.  A return code is a number from 0 through 255 that a program can "return" to the DOS shell.  (Unix uses note: DOS doesn't support more than 255 as the max for a return code, whereas Unix return codes are unsigned short integers.)

You can test return codes with the "If ErrorLevel" construct.  This can be used both at the command prompt as well as in batch files.

Most decently-written programs return 0 on successful execution, otherwise a value higher than 0.  ADB is a member of another large class of programs that returns 1 if there's some reason to be concerned, else a value higher than that.  In ADB's case, a return value of 1 is for warnings.

The DOS If ErrorLevel construct is special in that it's "true" when the return code is greater than or equal to the tested value.

For example, if the return code is 2, then this statment will always branch to the label FAIL:


If ErrorLevel 1 Goto FAIL

If you need to distinguish between more than a zero return code and a nonzero one, then you need to test for the higher error levels first.

For example, after running ADB:


If ErrorLevel 2 Goto CATASTROPIC_ERRORS
If ErrorLevel 1 Goto WARNINGS

For reasons unknown to me, Microsoft has refused to set return codes for any DOS commands.  This makes it particularly difficult to work with many of them.  For example, if you copy files from one place to another, and there's not enough hard disk space, the return code is still 0.


You can also test the value of DOS variables with the If statement.


If (%VARNAME%)==(VALUE) Goto VARNAME_IS_VALUE_LABEL

Unix users won't be surprised about the double equals signs, but others should note them.  The parenthesis aren't required, but if it turns out that VARNAME hasn't been set, they will save you from getting a syntax error.

For example:


If (%VARNAME%)==() Goto VARNAME_NOT_SET_LABEL

The If statement also allows you to check for the existence of files.


If Exist File.Dat Goto FILE_DOT_DAT_FOUND_LABEL

You can use wildcard characters in the file name (as well as path information.)


Although the DOS If statement doesn't support logical operators (such as "AND" and "OR") you can "cascade" your Ifs to create an implicit conjunction:


If Exist File1.Dat If Exist File2.Dat Goto FILE12_EXIST_LABEL

(The idea of the above label is that file 1 and 2 both exist.)


The unary negation operator ("NOT") is supported.


If Not Exist File1.Dat Goto FILE1_NOT_EXIST_LABEL

"Not" can also be used in the other cases where you can use "If" (e.g. in ErrorLevel testing, as well as in seeing whether a variable has a value).

Once again, I should remind you that DOS variables are case-sensitive.


DOS supports no numeric operations--all comparisons between variables and values are done as strings.  So, for example, "1.0" is not equal to "1".


You can use labels in DOS batch files for branching (in fact, I've been doing this all along in the examples).

Just prefix the label name with a colon (and don't put any excess spaces on the left).  For example:


:LABEL_NAME
case-sensitive.

I suggest that you avoid all characters except letters, digits, and underscores.

Although a label name, like a variable name, can begin with a digit, I personally think that this is bad form.

WARNING
Only the first 8 characters of labels matter.  If you have two labels, both of which begin with the same sequence of 8 characters, only the first will have any effect.


In fact there's no reason why your labels have to be constants when they're used.  It's perfectly okay to do something like this:


Set DEST_LABEL=VAR1_BAD_VALUE_LABEL
If (%VAR1%)==(1) Set DEST_LABEL=VAR1_IS1_LABEL
If (%VAR1%)==(2) Set DEST_LABEL=VAR1_IS2_LABEL
If (%VAR1%)==(3) Set DEST_LABEL=VAR1_IS3_LABEL
Goto %DEST_LABEL%

This is particularly useful for creating "pseudo subroutines".

For example:


Set FILE=File1.Dat
Set RETURN_TO_LABEL=RLABEL1
Goto SUBROUTINE
:RLABEL1
Set FILE=File2.Dat
Set RETURN_TO_LABEL=RLABEL2
Goto SUBROUTINE
:RLABEL2
Goto DONE
:SUBROUTINE
If Exist %FILE% Del %FILE%
Goto %RETURN_TO_LABEL%
:DONE

WARNING
Only the first 8 characters of labels matter.  If you have two labels, both of which begin with the same sequence of 8 characters, only the first will have any effect.

(I know I said this before, but I wanted to make sure that no one missed it.  It's very difficult to spot errors that arise from labels which are identical in the first 8 characters.)

This relatively useless DOS batch file sets the variable FILE to two different values and then branches to the label SUBROUTINE.

If the file whose name is in the variable %FILE% exists, then it's deleted, and we return to the label that's in the variable name %RETURN_TO_LABEL%.

Note that I had to "walk around" the subroutine by branching to the label DONE after both "subroutine calls" had been completed.

Once again, I should emphasize that variable names are surrounded by percent signs when they're used but not when they're set (assigned).

"Pseudo subroutines" can save you from having to create more DOS batch files than you really need to get the job done.  (You can use this same technique in any language that allows labels.)

If you've run any of the DOS batch files that I've used as examples, you might notice that the lines are written to the screen as they're executed.

This is very useful if you're trying to debug the file, but not so nice when the debugging is finished, and the batch file is being executed by a user, client, or customer.


If you don't want the lines to automatically echo to the screen, you can prefix them with an @-sign.  Let's see the previous example again:


@Set FILE=File1.Dat
@Set RETURN_TO_LABEL=RLABEL1
@Goto SUBROUTINE
:RLABEL1
@Set FILE=File2.Dat
@Set RETURN_TO_LABEL=RLABEL2
@Goto SUBROUTINE
:RLABEL2
@Goto DONE
:SUBROUTINE
@If Exist %FILE% Del %FILE%
@Goto %RETURN_TO_LABEL%
:DONE

Note that you can't and mustn't prefix a label with an @-sign.

(Footnote: many people used to write DOS batch files with the "Echo ON" and "Echo OFF" commands to turn echoing on and off.  I personally don't like to use them because you have to use "Echo ON" every time you want to communicate with the user.  I find the @-sign to be considerably more elegant.)

You can use the Rem (remark) statment to include helpful comments in your DOS batch files.

For example:


@Rem
@Rem Here's the first invocation of the
@Rem pseudo-subroutine:
@Rem
@Set FILE=File1.Dat
@Set RETURN_TO_LABEL=RLABEL1
@Goto SUBROUTINE
@Rem
@Rem RLABEL1: Return here after pseudo-subroutine call.
@Rem          We invoke the pseudo-subroutine again.
@Rem
:RLABEL1
@Set FILE=File2.Dat
@Set RETURN_TO_LABEL=RLABEL2
@Goto SUBROUTINE
@Rem
@Rem RLABEL2: Return here after pseudo-subroutine call.
@Rem          We're finshed and will branch to DONE
@Rem
:RLABEL2
@Goto DONE
@Rem
@Rem SUBROUTINE: Here's the pseudo-subroutine
@Rem
:SUBROUTINE
@If Exist %FILE% Del %FILE%
@Goto %RETURN_TO_LABEL%
@Rem
@Rem DONE: We jump here after all pseudo-subroutine
@Rem        calls are completed
@Rem
:DONE

Do not use any of the special characters (percent signs, or greater-than or less-than signs in your comments.) This is because Rem is still an "ordinary" DOS command.


Since labels can often lead to "spaghetti logic," I suggest that you use them in disciplined manner.  Branching should always be forward in the file, whenever possible (except for pseudo-subroutines).

It's good programming practice to proceed each label with a comment "block" (as you see above) that provides the name of the label, and the conditions under which a "Goto" will branch to it.

And while I've talked to many people who believe that labels are to be avoided whenever possible, there's no way to dispense with them in DOS batch language--because there's no concept of "code blocks."

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

15:  DOS Batch Files: Advanced

You can also pass parameters (AKA arguments) to DOS batch files.

These are very much like they are in Unix--referred to as %1 . . . %9.

For example, suppose the batch file called "Temp.Bat" looks like this:


@Echo %1
@Echo %2

If I execute:

Temp This.Dat That.Dat

then I'll see the following at the command line (as a result of the two Echo statements):


This.Dat
That.Dat


You might be wondering whether double quotes can be used to enclose Windows 95 file names, when passed as arguments to DOS batch files.

The answer is most assuredly "yes".  For example, if I execute:


Temp "C:\Program Files\Microsoft World Domination" Foo.Dat

then I'll see:


"C:\Program Files\Microsoft World Domination"
Foo.Dat

at the command line.

Note that the double quotes are preserved.  I'll say more about using double quotes in the next subsection.


What if you have more than 9 parameters to pass? No problem.  The DOS SHIFT command will assign the value of %2 to %1, %3 to %2, and so forth.

For example if the file Temp.Bat looks like this:


@Echo %9
@Shift
@Echo %9


Temp 1 2 3 4 5 6 7 8 9 10

Then it will output:


9
10

Note that SHIFT is the only DOS command that lets you modify the values of the %1 . . . %9 variables.  Otherwise, you can't assign them.


But there's one limitation to keep in mind here: the DOS command line can never be longer than 127 characters.  If it is, DOS will silently truncate it.  Bugs of this sort are surprisingly difficult to diagnose.


DOS has a special variable called %0, which refers to the current (batch) file.

This is especially useful for printing error messages, e.g. consider the following fragment:


Echo %0 had an error, see above!
Pause


There's another DOS command that will let you process a large number of files at once:


For %%V In (...) DO (something with %%V)

WARNING
the variable name here must be exactly *ONE* character.

(This is similar to the Unix script construct, except that it doesn't allow for a block of commands, and the variable name can only be a single character.)

For example, suppose you want to copy all the files A.Dat and B.Dat to the C:\Data folder:


For %%V In (A.Dat B.Dat) DO Copy %%V C:\Data\*.*

(Note how *.* is used as the file name here.)

WARNING
the variable name here must be exactly *ONE* character.

(I know I just said that, but it's critical to keep in mind!)

The items in parenthesis don't have to be constants.  They can be DOS variable names.  They can even be file names with wildcards.


This is a particularly useful variation that allows you to write "recursive" DOS batch files (i.e. DOS batch files that "call themselves").

Suppose you want to run a particular program, let's call it "MyPgm", with all the *.Txt files in the current folder.


For %%VE In (*.Txt) DO MyPgm %%V

The "for" construct isn't perfect.  If an error occurs, DOS will keep right on executing the operations.

If you want to make sure that the processing stops, you'll have to call a DOS batch file which checks to see whether an error indicator of some kind is present.

But this can be fairly awkward: for many applications, you'd prefer to minimize the number of DOS batch files.


It's tempting to think that you could write a DOS batch file like this, (assume that it's called "Temp.Bat"):


@If (%1)==() Goto FIRST_TIME
@Goto SELF_EXEC
@Rem
@Rem FIRST_TIME: Come here when we're called from command line
@Rem             We don't have any arguments the first time
@Rem
:FIRST_TIME
@Rem
@Rem Erase the error "flag" file.
@Rem This only exists when there's an error.
@Rem
@If Exist ErrFlag.Dat Del ErrFlag.Dat
@Rem
@Rem Now call ourselves "recursively"
@Rem  on each *.Txt file
@Rem Our goal is to execute MyPgm
@Rem  with each such file, but to
@Rem  make sure that we don't keep on
@Rem going, if there are errors.
@Rem
@For %%V In (*.Tst) Do %0 %%V
@Goto DONE
@Rem
@Rem SELF_EXEC: Come here when we have an argument
@Rem
:SELF_EXEC
@Rem
@Rem If ErrFlag.Dat exists, we shouldn't do
@Rem  anything else.
@Rem
@If Exist ErrFlag.Dat Goto ERROR_EXIT
@Rem
@Rem Otherwise we should run MyPgm
@Rem  on a text file.
@MyPgm %1
@Rem
@Rem Did MyPgm complete successfully?
@Rem If not, tell user!
@Rem
@If ErrorLevel 1 Echo %0 had an error: MyPgm--file %1!
@If ErrorLevel 1 Pause
@If ErrorLevel 1 Create0 ErrFlag.Dat
@Goto EXIT_SELF_EXEC
:DONE
@Echo %0 is done.
@Goto EXIT_FINAL
@Rem
@Rem ERROR_EXIT: Come here after ErrFlag.Dat exists
@Rem             Or when any errors detected
:ERROR_EXIT
@Goto EXIT_FINAL
@Rem
@Rem SELF_EXEC_EXIT: Come here when call ourselves
@Rem                  (and everything's okay).
:EXIT_SELF_EXEC
@Goto EXIT_FINAL
@Rem
@Rem EXIT_FINAL: All exits come here
@Rem
:EXIT_FINAL

This is a good simple example of a recursive DOS batch file which checks for errors.  If the program "MyPgm" returns something besides 0 (at "CALLING_OURSELVES_LABEL"), then we'll inform the user that there was an error, we'll pause (to make sure that the user "got" the error message, and finally we'll write a dummy line into the file "ErrFlag.Dat".

ErrFlag.Dat is our error "indicator" file.  If it exists, something went wrong.  Note that we erase it (if it exists) at "FIRST_TIME_LABEL".

Note also that the labels are longer than 8 characters; nevertheless, I've taken care to make sure that the first 8 characters are unique in each case.  (That is to say: no label "prefixes" another label for more than 8 characters.  Such bugs are very difficult to track down.)


This batch file is essentially correct, with the exception of one minor defect.

Take a look at this line:


@For %%V In (*.Tst) Do %0 %%V

You'll recall that I previously explained the use of "%0" to refer to the current batch file.  I suggested that it was useful in error messages, such as:


Echo %0 had an error, see above!
Pause

However in this case, it's actually being used to call the batch file "recursively" (i.e. to have it call itself:


@For %%V In (*.Tst) Do %0 %%V

As it happens, this is an almost-perfect scenario, except for one minor problem.

In DOS, you can't call a batch file without "chaining" to it. I.e. the flow of execution will not return to where you were.

So calling a batch file from another batch file isn't like calling a program from a batch file.

Let me be more explicit.

Suppose you call a program from within a batch file, e.g.:


...
MyPgm
...
After "MyPgm" is done, the statements afterward the call to "MyPgm" are executed.

Now suppose that "MyBat" is a DOS batch file.  If we write:


...
MyBat
...

the problem is that the statements after "MyBat" won't be executed.


There are two ways to overcome this problem.

First, if "MyBat" has no arguments, you can use the DOS CALL statement:


...
Call MyBat
...

On the other hand, if "MyBat" does have arguments, you can load a new command processor.

The way to do this is with the %COMSPEC% variable that's always defined on Windows 9x.


...
%COMSPEC% /e:4096 /c MyBat Arg1 ... ArgN
...

In this case, Arg1 ... ArgN stand for the arguments to the batch file.

So-o, to patch up our example, what we'd do is to change:


@For %%V In (*.Tst) Do %0 %%V

to:


@For %%V In (*.Tst) Do %COMSPEC% /e:4096 /c %0 %%V

The "/e:4096" part specifies the DOS environment size.  As I remarked earlier, you want to make sure that this is large enough to hold all of your "variable=value" pairs.  If it's too small, you can find yourself facing very nasty bugs.  (These bugs are "nasty" because they're hard to detect.)

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

16:  DOS Batch Files: Esoterica

You can stop a DOS batch file by entering control-C.  (Hold down the control key, and press "C").

If you put the PAUSE command in a DOS batch file, it will interrupt the processing and tell you to "Press any key to continue . . ."

Hit control-C at that point.  This will stop the DOS batch file.  If the file has been executed via new command processor (the %COMSPEC% technique that I described in the last section), then you'll only "break out" of the current invocation.


Most DOS editors (including DOS edit) will let you enter "graphics" characters by pressing the left alt key and using the numeric keypad. For example, you can produce things like this:


@Echo ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
@Echo Choose one of the options by entering a number:
@Echo ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
@Echo (1) Do this (default--hit enter or space bar).
@Echo (2) Do that.
@Echo (3) Do something else.
@BE2 "123"
@If ErrorLevel 3 Goto DO_SOMETHING_ELSE
@If ErrorLevel 2 Goto DO_THAT
@Goto DO_THIS

(This uses the ADB utility BE2, which is essentially the same as the DOS OPTION command.  It sets the ErrorLevel, depending on the key entered by the user.  Note that you examine the highest value of ErrorLevel first, because this statement looks for return codes that are greater than or equal to the specified value.)

The first Echo statement has the character 220 (decimal 220).  The second has decimal 223.  (Since you're viewing this in HTML, the character set won't give you the proper effect: you need to paste the results into a DOS text file and view them at the DOS command line.)


DOS will allow one level of "quoting" the double quote with the backslash character.  You simply preceed the double quote with a backslash.  For percent signs, use two in a row:

You can use the utility Repl to get less-than signs or greater-than signs into a text file.


Repl "$<A HREF=\"link.htm\">%% Salary Increases</A>" >index.html

Now the file index.html looks like this:


<A HREF="link.htm">%Salary Increases</A>


Some DOS programs open files with what's sometimes called a "shared open." (If you're a Unix person who uses C, this is the "sopen" call.)

If you're going to be writing to a "new" output file (i.e. not appending it), then you'll get the best results by making sure that this file doesn't exist.  ADB's utility "FileStat" is designed for precisely this purpose (as well as many others).

If you're using PkZip, you may find that you need to add the "-=" parameter to enable access to files that are being used by another process.

Sometimes, when running DOS batch files, you'll see the error "access denied" at the DOS prompt.  This means that Windows 9x is "holding" the file for some reason.  Once again, the utility FileStat can help you detect this problem . . . before it causes an error, and allow you to branch to a label in your batch file which takes care of the problem.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

17:  Other sections that you should read, even if you're only interested in DOS, and don't care about ADB

There are several other sections of this documentation that will help you get the most out of DOS:

  • The Awk Primer

    The Awk primer gives you a quick review of how to use GNU Awk (GAwk.Exe), the Free Software Foundation's version of Awk.

    I've taken some care to remind you of which sections are related to ADB, and which are useful in general.

  • The Awk (S)Printf Primer

    This is more about GNU Awk, but with a special emphasis on formatting strings.  Nothing there is relevant to ADB in particular.

  • The ADB Utilities

    I describe a large number of utilities; some of which were written by me, and some of which are GNU (Free Software Foundation) utilities.  These can vastly improve the ease and efficiency of your DOS-based applications.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

Next documentation section