home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
games
/
batutor.zip
/
BATUTOR.TXT
Wrap
Text File
|
1987-01-16
|
33KB
|
700 lines
Intermediate .BATch Tutor
-by Barry Simon
(c) Copyright 1986 by Capital PC User Group, Bethesda, MD.
[Editors note: This article was published November, 1986 in the "Monitor"
published by the Capital PC User Group. Material may be reproduced only for
internal use by other not-for-profit groups.]
One of the tools that most distinguishes the experienced DOS user from others
is the effective use of BATch files. In this article, I will discuss some of
the more advanced features of BATch files and their commands. I call this
tutorial "intermediate" because I have tried to write in a manner accessible
to those with only a little experience writing BATch files.
------------[ Simple BATch files ]------------
To begin with, a BATch file is a set of DOS commands which you place together
and which you can issue by just typing the name of the BATch file. The
classic example is the BATch file which changes to the directory containing
Lotus' 1-2-3 and then runs 1-2-3. The same idea can be carried much further:
for example, when I execute my word processor with a batch file, it
-- loads the proper set of macros in my keyboard macro program;
-- makes a mark using Kokkennen's MARK/RELEASE package;
-- loads my thesaurus;
-- loads the appropriate mouse menu program;
-- runs the word processor, and
-- after I am finished with the word processor, clears the macros and
runs RELEASE to boot the thesaurus and mouse menu from memory.
BATch files must be pure ASCII text files with separate commands on distinct
lines separated by carriage return/line feed pairs. To create your BATch
files, you can use EDLIN, a text editor, or any word processor that produces
straight ASCII text files.
BATch programs can contain DOS commands, application program commands, or a
variety of specialized programming features that are known as BATch commands.
------------[ BATch Commands and Features ]------------
Parameters......
Your text editor may allow you to specify a text file to use as a parameter
on the command line loading it. You would like to specify the file name as a
parameter on the command line calling a BATch file to start your editor and
have this file name passed on to the editor when it is loaded. This is quite
easy. If your editor is called EDITOR.EXE and you load it via a BATch file
called foo.bat, you need only make the line calling the editor say:
editor %1
and then call up the BATch file as
foo filename
When the BATch processor comes to the %1, it looks for the first parameter
following "foo" and replaces %1 by that parameter, in this case by filename.
To be more precise, DOS parses the command line calling the BATch file into
distinct "words" separated by one of four delimiters:
<space> , ; =
That is, it looks for strings of allowed characters separated by one or more
of these special four. Any of the 256 ASCII characters are allowed in the
strings except for these four delimiters, the three redirection characters
(<,>,|) and the ASCII nul. The first word on the command line is assigned
the value %0, the next %l, etc. Normally, %0 is just the name of the BATch
file but since "." is not a delimiter in parsing the line but is a delimiter
in ending file names, if you have a BATch file foo.bat and type in
foo,cpcugisgreat
foo.bat will be run and %0 will have the full 17 character string assigned to
it. Similarly, since DOS knows that file names are no more than 8
characters, the BATch file 12345678.bat will be run if you type in
12345678ABCDEFGHIJ
but %0 will have an 18 character string. These are admittedly curiosities
but DOS curiosities have a knack of being useful sometimes. In a real sense,
DOS assigns as many parameters as there are words on the command line, but
initially you can only access the first ten as %0 through %9. Any place that
%1 appears in the BATch file except as %%1, it will be replaced by the first
word after the filename even if that word is the empty word. Any other time
that the symbol % appears in the BATch file, DOS will strip the %-sign away
except that %% is replaced by a single percent and %%1 becomes %1 so if
foo.bat has the single line:
echo %%1 has the value %1
then typing
foo junk
will issue the message
%1 has the value junk
There is no limit on the size of any individual parameter other than the
overall limitation that the entire DOS command line can contain no more than
a total of 128 characters.
To summarize: any time %i (for i=0,1,...,9) occurs in the file except as a
%%i, it will be replaced by the ith string in the command line.
The real limitation of BATch file parameters is that they are not variables.
You cannot manipulate them by parsing them and cannot change their values.
Labels......
As a preparation for discussing BATch file GOTO commands, I need to discuss
labels. Any line beginning with the character ":" will be skipped by the
BATch processor when it gets to it. This means that you can use such lines
as remark lines which will not appear on the screen even if echo is on (in
which case lines beginning with rem do appear). You can also place the
redirection characters <,>,| on such a line (but you cannot place such
characters on a "rem" line). And % signs are not treated specially on such
lines.
While DOS ignores such lines, the string following the : becomes a label for
the GOTO command which I'll discuss next. The first word or the first eight
characters of the first word become the name of that label. You can also
place comments after a label name if you separate these comments with a
space.
GOTO......
The most significant way in which BATch files go beyond the DOS command line
concerns two logical control structures, the GOTO and the IF commands. The
line
goto <label>
will send the BAtch file to the line immediately following the line on which
the label appears. If the label appears more than once, its first appearance
in the file is used. If the label does not appear, the processing of the
BATch file is abruptly ended with the message "label not found."
GOTO's can be used for either branching or some rather crude looping. Here
is a simple example of branching. Suppose that you wish to send control
codes to your printer easily from the DOS command line. You might prepare
little files like ff.txt containing a formfeed (control- L), or boldon.txt
with the codes for turning bold face on, etc. Then you could write a
print.bat file which began:
goto %1
:ff
copy ff.txt prn
goto end
:boldon
copy boldon.txt prn
ETC
with a label ":end" as the last line of the file.
One problem with the limited logic allowed by BATch files is the difficulty
of error checking. With the above, if you forget to put in a parameter or
put in an illegal value, you would get the rather inelegant "label not found"
message. Alternatively, you could replace the "goto %1" with separate lines
such as:
if %1 = = ff goto ff
and then place an error message, hardly a neat solution.
PAUSE......
The next BATch command that I'll discuss, PAUSE, unlike GOTO and paramaters
makes sense at the DOS command line. For straight DOS usage, this is
pointless but for environments like CED or TallScreen which allow multiple
commands on one line, it can be useful. What PAUSE does is display the
message:
Strike a key when ready ...
and pause the processing of the BATch file until a key is struck. Before the
message is displayed, the keyboard buffer is flushed to prevent any stray
keystrokes left over from previous operations from bypassing the effect of
the PAUSE command.
There are three rather distinct uses of the PAUSE command. The most well
known is to allow the user to take an action like inserting a diskette into a
drive. Often, you will want to echo a message to the screen before the PAUSE
command such as:
echo Place a diskette into drive B: and ...
pause
A second use is to allow the user to see the output of some program before
the BATch file continues. Without the PAUSE, the output might disappear too
quickly to absorb. A third use that we'll see later is an extremely crude
device for user input.
The IF Command......
The second and last element of flow control provided by DOS is the IF
command. Like pause, it also makes sense at the DOS command line. The
syntax is
IF (not) <comparison> <consequence>
The not is an optional part which we'll explain later. Comparison is limited
to three types:
-- A test for the equality of two strings;
-- A test for the existence of a file; and
-- A test of the "error level."
If the comparison is true, then the command in "consequence" will get carried
out. If the word "not" is included, then <consequence> is carried out only
if the comparison fails. While consequence is typically a GOTO statement,
any acceptable DOS or BATch command is allowed. You can even have the
consequence be a second if statement as in
if not %1 = = ff if not % 1 = = boldon goto error
As the last line shows, the syntax for checking strings is to use two equal
signs. Strings are sequences of characters not including the standard
delimiters (space, comma, semicolon or equal) or redirection signs. These
redirection signs but not delimiters can appear if the string or part of the
string is surrounded by single or double quotes. If an illegal string is
used, DOS will reward you with "bad command or filename." There is a standard
problem faced by users first exposed to BATch files. Often, you will want to
test for an empty string, for example to give an error message if the user
failed to provide a necessary parameter. Empty strings are not allowed so
that the line
if %1 = = echo whoops
will yield "syntax error" if %1 is empty, and "bad command or file- name" if
%1 has the value "echo" unless of course you have a program named "whoops."
The way out of this problem is to use the fact that %1 is replaced wherever
it is and add a dummy parameter as in
if a %1 = = a echo whoops
The possibility of looking for a file provides essential error checking. A
common example of its use is to fix the deadly move BATch file:
copy %1 %2 \ %1 erase %1
This may seem like a great way of moving a file from one directory to another
so that
move foo.txt C: \ junk
will move foo.txt from the current directory to junk. But if the directory
junk doesn't exist, the first line will give the error message "Invalid
directory" and the second line will erase the file which has NOT been copied.
Thus, as a protection you should add before the "erase %1" line
if not exist %2 \ %1 goto end
with an appropriate label and error message. There are many other places
where such error checking can be invaluable. Unfortunately, "if exist" works
with path names only in DOS 3.x and not in DOS 2.x.
The final if comparison, "if errorlevel," is useless within the context of
pure DOS commands since no DOS command (before DOS 3.2) sets errorlevel. But
the DOS technical reference describes how a program can set this parameter
and if you have a program that sets it, this comparison is useful.
But I must warn you that the comparison
if errorlevel 2
is TRUE not only if the value of errorlevel is 2 but if it is 2 or greater.
Beginning with DOS 3.2, several external DOS commands such as BACKUP,
RESTORE, and FORMAT set what the DOS manual calls "exit codes" which can be
tested with "if errorlevel."
Nested and Chained BATch Files......
It is possible to make rather elaborate collections of BATch files which call
one another. The simplest is the equivalent of a GOTO. If the name of
another file appears as a line in one BATch file, the BATch file will begin
and you will NOT return to the first BATch file when the second one ends.
Particularly since the BATch control structures (GOTO and IF) do not include
CALL/RETURN processing of subroutines, one would like to be able to call a
second BATch file as a subroutine and return to the first BATch file when the
second one finished. Many books, especially the older ones, will tell you
that this is not possible. However, in DOS 2.x and later, there is a method
of doing precisely this kind of subroutine call. This is an example of
something which is not undocumented but rather so badly documented that many
experts did not realize its potential until some time had passed. The reason
that an ordinary call to a second BATch file does not return you to the first
is that COMMAND.COM is only able to keep track of one BATch file. The
solution is to load a secondary copy of COMMAND.COM to process the second
BATch file. The correct syntax is
command/c foo
to call foo.bat from another BATch file. When foo ends, processing of the
first BATch file will continue on the next line.
Several warnings are in order concerning this command. As you may know, DOS
has both internal commands like COPY and external commands like FORMAT. That
is, once COMMAND.COM is loaded during initial bootup, COPY becomes an
available command while FORMAT is a stand alone program provided separately
on the DOS disk, which must reside in the default directory or in the path to
be available in the user. You might think that COMMAND was an internal
command but it is external. That is, in order for a line like
command/c foo
to work, COMMAND.COM must be available in the default directory or in the
path. In addition if you leave an old version of COMMAND.COM somewhere on
your hard disk and that happens to be the one first found when this line is
processed, you will get a message "incompatible DOS versions." Finally, there
is a warning about the SET command discussed in the section below on global
variables.
FOR...IN...DO
FOR...IN...DO is one of DOS' most powerful and least appreciated commands.
It can be used at the DOS command line or in a BATch file with slightly
different syntax. The syntax at the DOS command line is
for %a in (<list>) do expression (%a)
The use of a in %a is not important; you can use any letter or number or
even extended ASCII code so long as it appears in all places. The % is
important and since %'s get stripped from BATch files, the syntax in a BATch
file must be "for %%a...". The keyword "do" must appear or you will get a
"syntax error" message. Within the () can appear a list of ASCII strings
separated by the standard delimiters. Following the keyboard "do" can be any
command with %a as a parameter which will be successively replaced by the
values listed within (). For example
for %a in (file1 file2 file3) do copy %a prn
will issue three separate commands copying the three files to prn.
The power of the FOR...IN...DO construction comes because you can include
wildcards and DOS will substitute in turn each filename satisfying the
wildcard, so for example.
for %a in (file?) do copy %a prn
would do the same thing as the above command if there were no other files
with the name file? Therefore, the greatest use of FOR...IN...DO is to force
programs which don't understand wild cards to understand them none-the-less!
For example, when I discussed file viewers, I talked about both LIST and
FILEVIEW. LIST allows you to give wildcard filenames so "list*.doc" would
successively view all files with a doc extension. FILEVIEW does not have
this built in but you can do it yourself: rename fv.exe fv@.exe and make a
one line BATch file called fv.bat saying
for %%a in (%1) do fv@ %%a
and suddenly FILEVIEW also has this capability.
You can also force commands which don't treat wildcards "properly" to do so.
For example, if you want to change the date/time stamp on a file foo. txt to
the current date and time, the command
copy/b foo.txt+,,
will do precisely that. If one replaces "foo.txt" in the above command by
*.*, DOS will create one file which is the combination of each file in the
current directory, probably not what you intended. To change the date/time
of all files use
for %a in (*.*) do copy/b %a+,,
You can combine multiple commands and wildcards as in
for %a in (*.pas*.com) do copy %a A:
If you want to stop such a command before it has run its course, Ctrl-C will
give you the opportunity to break the loop. In addition you should be warned
that a FOR...IN...DO loop is like a BATch file; if the expression called
after the keyword "do" involves a BATch file, processing will not return to
the FOR...IN...DO loop. It will only be processed one time even if you have
several possibilities in your list. As happens for BATch files, placing
command/c will prevent the chain breaking so
for %a in (*.*) do command/c foo %a
issued at the DOS command line would run the BATch file foo.bat successively
with each file in the default directory as a paramter.
The BATch processor is rather inefficient. It reads only one line of the
file into memory at a time (try including a line like "erase foo.bat" in a
BATch file to see what happens) although it keeps its place by counting the
byte offset (try using your editor on foo.bat as a line in foo.bat to explore
this). By using the FOR...IN...DO command to reduce the number of lines in a
BATch file, you can speed up processing by a noticeable, although not
spectacular, amount (perhaps by 10%). For example, if you have a large RAM
disk and routinely copy several directories to it during bootup try:
for %%a in (path 1 path 2) do copy %%a \ *.* D: >nul
Two warnings about this procedure: you cannot include a command with its own
parameters in the list since DOS processes the list in () one word at a time.
Second, for technical reasons, I strongly recommend against loading resident
programs in such a statement.
SHIFT......
As I described above, when DOS parses the input command line to a BATch file,
only the first 10 words are available as %0 to %9. However, DOS keeps a
record of the entire line. One of the things that the SHIFT command does is
provide you with access to the other parameters. A line with the single
command SHIFT drops %0 changes %1 to %0,..., %9 to %8 and makes what was the
eleventh word on the original command line into the new %9.
Additional calls to SHIFT repeat this process.
If SHIFT were only good for accessing parameters beyond the initial ten, it
would be of limited use. I cannot find any interesting use of this aspect of
the command. Its real use lies in the possibility of having a real loop
within a DOS BATch file. Here is a sample "touch.bat" expanding the one line
procedure for updating the date/time stamp of a file:
:top
if %1x=x goto end
for %%a in (%1) do copy %%a+,,
shift
goto top
:end
With this BATch file, you can issue the command touch followed by several
parameters, each with wildcards. The basic operation is applied to each file
meeting any of the filespecs listed as parameters. Of course, you could
probably do just as well with the single line.
for %%a in (%1 %2 %3 %4 %5) do copy %%a+,,
While I can develop considerable enthusiasm for the FOR...IN...DO command,
SHIFT does not evoke much excitement!
ECHO......
Next, we turn to the issue of displaying information on the screen, the
primary method of communication between the writer of BATch file and the
user. Even if you are writing BATch files for yourself, it pays to expend
some effort in making attractive, instructive displays. By default, every
line in the BATch file appears on the screen. While this has the potential
advantage of showing the user what is going on, usually the display is so
fast that it is more distracting than useful. You can turn off the automatic
display of commands to the screen with the command.
echo off
When echo is off, you can display messages by preceding the desired
communication with the keyword ECHO. The default for BATch file should be
echo off and there are patches for COMMAND.COM to make that the default. I
have avoided this patch because such a patch is not immediately available for
new versions of DOS. Unless you make this patch, most of your BATch files
should begin with
echo off
cls
It is not necessary to turn echo on before exiting a BATch file; it is
turned back on automatically. You can suppress the prompt on a DOS command
line by typing "echo off" at the DOS prompt and then "echo on" is necessary
to restore the default.
ECHO can be a useful command. Its message is sent to standard output which
means that you can redirect it and so use it to send codes to your printer.
But be warned that a CR/LF pair is always appended to an echo line so
echo ^L>prn
(where ^L means control-L the form feed character) will not send only a form
feed to your printer, it will send an extra line feed. Also, you will not be
able to send escape codes to your screen or printer directly from the DOS
command line. DOS reacts to your <Esc> key by aborting the current command
instead of placing an escape character at the cursor. With many editors you
can put escape characters into a file and so write BATch files to send escape
codes to the screen or printer.
One character you may want to use is ^G (Control-G entered by depressing the
control key and hitting g). This is the "BEL" character and will beep when
sent to the screen. So
echo ^GYou made an error
will catch the user's attention. But please control yourself: avoid putting
several ^G's together. And with most printers
echo ^G>prn
will beep the printer.
A famous problem is how to use ECHO to make blank lines. A BATch file
command line with the single word "echo" will not work as this will get the
response "echo is on" or "echo is off". DOS 2.x had a celebrated undocu-
mented feature: "echo<space>" did produce a blank line by relying on this
undocumented feature caused grief when DOS 3.x gave the "echo is on/off"
response. Some vesions of DOS have had
echo .
(note the period) produce blank lines but this has not always been true and
had led to some rather fancy programs with installation files showing bunches
of dots on the screen. There is a rather simple solution. To get a blank
line try
echo <char 255>
where <char 255> means including the character with ASCII code 255. You
can't enter this in all editors but in many (e.g. EDLIN), you can by holding
down the <Alt> key and hitting 2 5 5 on the numeric keypad. Lest you be wary
of using an undocumented feature of DOS, this trick merely relies on the
documented feature of "echo" to send any character even those with codes
above 128 to the screen:<char 255> is a blank character. You can also use
one of these characters to anchor down a message that you don't want to start
in column one.
Even if echo is off, the last line in the BATch file will appear on the
screen if that line does not end in a carriage return /line feed pair. For
this reason, you will probably want to be sure that the last lines in your
BATch files have such a CR/LF pair at the end. The exception is if the last
line is "cls". In this case the echo to the screen is unimportant and adding
a CR/LF will sometimes place the prompt on line three instead of line two.
------------[ Using ANSI.SYS ]------------
If you are writing for a "mass market," you cannot assume that the user of
your BATch files has ANSI.SYS installed but if you are writing for yourself
or for a colleague, you can be sure it is installed. ANSI.SYS provides a
simple way of controlling colors and, to get really attractive screens, the
location of messages. You should consult your DOS manual (or the DOS
technical reference for DOS 3.x) to learn how to move the cursor. For
example, if you want to start with echo off and then only erase the line
"echo off" without clearing the whole screen, try:
echo off
echo <esc>[A<esc>[K
------------[ Input the Inelegant Way ]------------
One of the weaknesses of the DOS BATch processor is its inability to accept
input from the user. This is of importance not only when writing for others.
You might want a BATch file to run a program and then ask if you wanted to
make a backup. Of course, if you knew the answer to this backup question in
advance you could write the BATch file to get such input as a parameter when
the BATch file was loaded but there is no simple way to get input once the
BATch file is running. The best way to overcome this lack is to use one of
the programs I'll be discussing in later articles in this miniseries. Lack-
ing that, I know of two methods to get user input just using DOS's tools.
First, Control-Break (or Control-C) will stop a BAtch file (or rather give yo
the message "Terminate Batch file(y/n)?") and so you can point out to the
user the option that is always available any ways. For example, if backing
up is all that is left you could put in the lines:
echo To prevent backup hit Control-Break; otherwise
pause
Since you can accidentally brush a key, this is hardly an ideal solution.
Also, you can end a BATch file by displaying a menu with choices labelled
"a,b,c" and have BATch files called a.bat, b.bat, c.bat to run depending on
the user's response.
------------[ Global Variables ]------------
If you chain or nest BATch files, it is easy to pass parameters between them
by putting the parameters in the command line calling the second BATch file.
But what about BATch files called at different times. For example, you may
have noticed that the a.bat,... procedure above seems to have the disad-
vantage that you can only use it for one menu unless you use different
directories or different letter choices. Wouldn't it be better if there were
a place to put "global variables" so you could set menuchoice=1 before
displaying a menu and have a.bat do different things depending on the value
of "menuchoice". Well, DOS has precisely such global variables although a
part of the procedure is undocumented.
When COMMAND.COM is initially loaded, it sets aside a region of memory as
"the environment" which by default is 160 bytes.
The environment is intended primarly to store the location of COMMAND.COM
when its transient portion needs to be loaded, your path and prompt and
information that the user can provide various programs. However, you can
also use it to store global variables for communication between your BATch
files.
Placing information into the environment is a documented DOS command. You
use SET. Thus
SET Name = string
will define a global variable "name" to have the value "string". As usual,
"name" doesn't distinguish between lower and upper case; if you look at the
environment by typing "SET" with no parameters, the variable will appear as
NAME = string
Upper and lower case are distinguished in strings. Notice also that spaces
count so that the command
SET name = string
will define another variable "NAME" (note the space).
Getting the value of a global variable is easy from within a BATch file. If
a name appears between percent signs, then DOS will replace the string %name%
by its environmental value. Thus if you issued "set foo=fun" and later have
a line like
if %foo%=fun goto success
then the BATch file will go to the label success. If foo has no current
value, %foo% is replaced by the empty string. Several warnings are in order.
First, this procedure is undocumented. However, it has been constant from
DOS 2.0 through 3.2 and is so close to a documented procedure available to
programs that it is as likely to remain in DOS as anything that is not
documented. Second, while you can use the SET command to define variables
whose names have spaces in them or whose name begins with a numeral, you
cannot use %name% to access such variables.
A final warning. If you use a command/c to nest a BATch file, DOS makes a
copy of the environment for the new shell that runs the nested BATch file.
Anything in the original environment is in the new one so gloval variables
are available in the new shell. However, any changes made in the environ-
ment by the nested BATch file via a SET command are only saved in the
secondary environment and will be lost when you return to the original BATch
file.
What are global variables good for? I have placed today's date in English
(that is January 1, 1980 rather than 1-1-80) in my environment a bootup and
then I have a letter.bat which makes a copy of a template with my address and
my word processor's formatting command and I append to this copy via
echo (char 255) %date% >>%1
------------[ Key Stacking ]------------
Wouldn't you like to call up TURBO PASCAL in a BATch file which automatically
answered Y to the opening question, hits W, supplies the name of a file that
you passed to the BATch file as a parameter and then hit E for edit? Or
wouldn't you like to have a key struck automatically in response to the IBM
logo and "hit any key to continue" at the start of so many IBM programs?
BATch files need a command that lets you prestack some convenient strokes in
the keyboard buffer.
However, there is one crude way of providing keyboard input with DOS tools if
you can provide all the required input in advance. For example, if you want
an "erase*.*" command in a BATch file and would like to avoid having to
answer "are you sure(Y/N)?", prepare a file, "yes.txt" with the single line
"Y" (and including a CR/LF) and place the line
erase *.* <yes.txt
in the BATch file. Two warnings are in order here. Be sure you have a
complete set of responses or else your system will hang. In response to the
"are you sure," you must respond Y followed by <Enter> so if you left the
CR/LF out of yes.txt, "erase" would patiently wait for the <Enter> and
wouldn't take it from the keyboard since you told it to only take input from
yes.txt. Second, you cannot redirect input and output to a BATch file as a
whole but you can redirect input or output of individual commands if the
commands use standard I/O. Thus, you cannot make a file, 2yes.txt. with two
yes liens and a foo.bat with two lines saying "erase *.*" and use
"foo<2yes.txt." Foo will still insist on input from you.
------------[ Summary ]------------
BATch commands provide the end user with a powerful set of programming tools
to develop custom and innovative solutions for everyday computer needs.
In future articles, I will describe some programs that can be used to enhance
the BATch commands and further extend and improve this convenient programming
tool.
[end of article]