Batch Guide

This is an attempt at explaining the MSDOS batch language. It is not
complete, just the basics. For more information on individual commands
refer DOS's built-in HELP command. Some familiarity of DOS is assumed, you
should already know what directories are and how to use common commands
like CD, MD, DEL, RENAME etc.

This is a work-in-process, more chapters will follow as I have the time to
write them.

Table of Contents

   * Elements of the batch language
        o Variables
        o Redirection and Pipes
        o Labels, Conditions and Branching
        o Subroutines, CALL and FOR
   * Launching programs
        o The path...
        o Batch for running a virus scanner
        o Batch that unzips and scans multiple ZIP files
        o COM utility to strip .EXT from filename
   * Menus for programs
        o Simple example game menu
        o Using menuing systems
   * Obtaining user input
        o Batch routine for entering strings
   * Configuring your system How to set up SHELL and ANSI

All of the examples assume English DOS 6, some may run under DOS 5 but
don't count on it. DOS 6 adds features which are very useful to batch
programmers, like CHOICE and a version of FIND that returns an errorlevel.
---------------------------------------------------------------------------

Elements of the Batch Programming Language

The best way to learn batch is to experiment while refering to the HELP
command, it explains everything. Batch programs are essentially sequences
of DOS commands that 'type themselves' when the batch file is run.

Batch files consist of control elements, internal DOS commands and external
commands or programs. With a little ingenuity one can duplicate most of the
functions of a general purpose language, but doing any kind of math is
tricky, there are no arithmetic commands at all. For the types of things
batch is used for, this is not much of a problem.

Variables

Batch uses the percentage sign (%) to mark variables. The set command is
used to assign and clear variables. When DOS reads the batch file, strings
like copy %var1% %var2% will be expanded to read say copy source.fil
dest.fil (assuming that's what they're set to) before feeding the line to
the command interpreter. %% is reduced to % when interpreted, so the
at-the-prompt commandfor %a in (1 2 3) do echo %a has to be written in a
batch file as for %%a in (1 2 3) do echo %%a.

Variable names have eight significant characters (I think) and are always
stored as upper case (except for the 'windir' variable added by Windows).
In addition to user-set variables, the entire command line is passed to the
batch as the read-only variables %0 to %9. %0 is the actual batch name as
typed, the rest are parameters. The shift command moves everything down by
one allowing parameters past the ninth to be retrieved (this wipes out the
%0 parameter so if used for the batch to call itself it must be saved to
another variable).

The following batch illustrates the use of variables...

     @echo off
     set var1=Hello
     set var2=World
     echo %var1% %var2%!
     set var1=
     set var2=

Explanation - the first line prevents the commands from being displayed,
the @ in @echo off keeps that line from displaying. The set command is used
to set two variables to "Hello" and "World". Next, echo is used to display
the two variables to the screen followed by "!" producing the classic Hello
World! display. Finally the two variables are cleared to keep them from
needlessly consuming environment space.

Speaking of environment, you should specify more space than stock DOS gives
you by using a CONFIG.SYS line similar to...

     shell=c:\command.com /e:1024 /p

The number after /e: specifies how much space to set aside, usually 1024 is
plenty. You can also execute command /e:5000 /c progname if you need a
bunch of space. This can be included inside the batch itself. For quickies,
especially if you wish to restore all variables to their original state
after testing something, just enter command /e:5000. Type exit to quit the
command shell and return to the previous environment.

Redirection and Pipes

Normally, input is taken from the keyboard and output goes to the console.
Redirection allows input and output to refer to a file or device instead.
Pipes allow the output of one program to be used as input to another
program. These symbols only work with programs that read from "standard
input" and write to "standard output" but fortunately this includes most
DOS commands.

   * The < symbol causes file to be fed to the program as input.
   * The > symbol causes the program's output to be sent to the following
     file or device.
   * The >> symbol causes the program's output to be appended to the file
     or device.
   * The | symbol (the pipe) causes the output of the preceding program to
     be sent to the following program.

The following example shows how to use redirection with the FIND command...

     @echo off
     find "%1"<%2>nul
     if not errorlevel 1 echo %2 contains %1

If saved as say DOESIT.BAT, entering doesit "Word" text.fil will print
text.fil contains "Word" if the file TEXT.FIL contains the string "Word"
(at least under DOS 6). Since we're not interested in the actual output of
the FIND command, it is redirected to the nul device.

Labels, Conditions and Branching

A label is any line that begins with a colon. Comments in batch code can be
made by using a double-colon, this is better than using the REM command
because labels are processed before redirection symbols. ::<remark> causes
no problems but rem <remark> produces errors.

The goto command is used to transfer control to another part of the batch
file. For example...

     :: test goto's
     @echo off
     goto start
     *** This text can be anything ***
     *** because it will never run ***
     :start
     echo Done.

The decision mechanism in batch is the if command. It can be used to
compare one string to another, determine if a file exists or determine the
errorlevel returned by a previous command. If the evaluation is true, the
rest of the command is executed. The not modifier reverses the evaluation
results. Examples...

     if not %var%.==. goto got_var
     if exist MYFILE.DAT goto got_file
     if errorlevel 5 echo Errorlevel is equal or greater than 5
     if not errorlevel 4 echo Errorlevel is less than 4

Notice the periods in the if %var%.==. example, they keep empty variables
from producing syntax errors. '%var%. is equal to . only if the string is
empty. The way the command is worded it branches to :got_var only if %var%
is not empty. Read the wording in the if errorlevel command, any errorlevel
equal or greater than 5 is evaluated as true.

Subroutines, CALL and FOR

Most of the elements are in place, but still no subroutines. These can be
tackled either by defining a return value and GOTO'ing the routine, which
GOTO's to the value of the return variable upon completion. For example...

     set return=next1
     goto subroutine
     :next1
     -- bla bla --
     goto end
     :subroutine
     -- bla bla --
     goto %return%
     :end

A more eligant way is to use a branch at the top of the batch that branches
to the subroutine. This can be combined with the for and call commands to
perform a sequence of steps. Here is an example that prints the names of
BAT files in the current directory...

     @echo off
     if %1.==Sub. goto %2
     for %%a in (*.bat) do call %0 Sub printbat %%a
     goto end
     :printbat
     echo %3
     :end

Launching programs

One of the most useful aspects of batch is its ability to set up custom
environments for running programs. Here is a typical made-up scenario:
Suppose you have a game that requires you to change to say the C:\GAMES\MUT
then run the program MUTANT with the command line parameter /NSB. Rather
than typing all that, just put it into a batch and place it in a path
directory.

The path - this is a list of directories held in the %PATH% variable that
DOS uses to find programs without having to specify the directory it's in.
For example, the default path in a simple setup might read (from
autoexec.bat)...

     path C:\DOS;C:\WINDOWS;C:\

Each directory is separated by a semicolon. When a command is typed first
DOS tries the current directory. If not there it begins searching each
directory listed in the path line. It is convenient to place batch files in
a path directory. If you haven't done so yet, make the directory C:\BATCH
(for example) and add it to the path line, as in...

     path C:\DOS;C:\WINDOWS;C:\;C:\BATCH

Any batch file now placed in C:\BATCH can be run from anywhere without
having to change directories. Now, back to the mythical example, let's put
all of the required commands into a file called say MUTANT.BAT and place it
in C:\BATCH (on the path now)...

     @echo off
     c:
     cd \games\mut
     mutant /NSB

The first line turns off command echo (contained at the beginning of almost
all batch files), the next line ensures the C drive is active, then it
changes to the correct directory using the cd command and runs the game
with the correct command line parameter.

Here is an example for a virus scanner that does not change the current
directory, but instead calls a program in another directory. In this
particular example, if the batch is called without parameters defaults are
supplied instead...

     @echo off
     set parm=%1 %2 %3 %4 %5 %6 %7 %8 %9
     if %1.==. set parm=. /nomem /sub
     c:\scanners\scan\scan.exe %parm%
     set parm=

The specific commands, directories and parameters will vary depending on
the software and where it is installed. The command line is stored in the
variable %parm%, if the first parameter %1 is empty, %parm% is set to a
useful default, for SCAN this translates to "scan the current and all
subdirectories under it, do not scan memory". If this batch was saved as
say SCN.BAT into a path directory (got that C:\BATCH directory yet?) any
directory branch may be scanned by just typing SCN instead of having to
type the directory\command parameters.

This next batch is more sophisticated, it unzips all ZIP files in the
current directory then optionally moves the ZIPs to a backup directory
and/or scans the new files with several scanners. First the batch...

:: UNZIPDIR.BAT - Unzips multiple zip files to individual directories
:: then optionally scans them for computer viruses. When complete the
:: original zips can be moved into a backup directory.
:: STRIPEXT.COM and PKUNZIP.EXE must be somewhere on path.
:: Modify the scanner commands to match your software!
:: Requires DOS 6 unless modified, uses CHOICE and MOVE
@echo off
if %1.==Loop. goto %2
::=== run a new shell with room...
if exist *.zip command /e:2000 /c %0 Loop shell
goto done

:shell
::== set zipdir=where to move original ZIP files
::== (if more than 1 deep upper subs must exist!)
set zipdir=ZIPFILES
::=== loop for each zip file...
for %%a in (*.zip) do call %0 Loop unzip %%a
goto movezips

::=== extract dirname and unzip...
:unzip
echo Unzipping %3...
echo %3|stripext>strip$.bat
call strip$.bat
del strip$.bat
md %fn%
pkunzip %3 %fn% -d -o > nul
if errorlevel 1 echo File %3 contains errors!
goto done

::=== move zips?
:movezips
echo Move ZIP files to %zipdir%?
choice /c:ny>nul
if not errorlevel 2 goto scanfiles
if not exist %zipdir% md %zipdir%
move *.zip %zipdir%>nul

::=== scan files?
:scanfiles
echo Scan files?
choice /c:ny>nul
if not errorlevel 2 goto done

::== This section depends on your software, modify to your system
::== As written it calls HtScan (with custom signatures), TBSCAN,
::== F-PROT and TBSETUP. Use parameters to scan the current and
::== all subdirectories below the current directory.

::=== HtScan...
c:\virus\htscan20\htscan.exe *.* /A /B- /M-
::=== Thunderbyte TBSCAN...
c:\thunder\tbscan /hr
if errorlevel 1 pause
::=== F-Prot...
c:\fp\f-prot . /command /nomem /analyse /paranoid /guru
if errorlevel 1 pause
::=== Thunderbyte checksummer...
c:\thunder\tbsetup -nh -no

::=== return to caller
:done

This batch uses a very small machine code program to strip a filename of
its extension and add 'set fn=' in front of it to allow the batch to call
it to set the variable. The following batch will make the file
STRIPEXT.COM...

@echo off
echo e 100 e8 16 00 b4 08 cd 21 3c 00 74 0c 3c 2e 74 08 88>strip$$
echo e 110 c2 b4 02 cd 21 eb ec cd 20 ba 21 01 b4 09 cd 21>>strip$$
echo e 120 c3 73 65 74 20 66 6e 3d 24 00>>strip$$
echo n stripext.com>>strip$$
echo rcx>>strip$$
echo 2a>>strip$$
echo w>>strip$$
echo q>>strip$$
debug<strip$$>nul
del strip$$

Place the files UNZIPDIR.BAT and STRIPEXT.COM in any path directory.
PKUNZIP.EXE too if it's not already on the path. The section that calls the
virus scanners is just what I use myself, your scanning software will
require different commands unless you happen to use what I do. Even then
you'll have to edit the directory names, so be prepared to edit if you want
use this batch.

OK, now I'll attempt to explain how it works, if you don't understand the
commands I'm using yet don't worry, it will come as you become more
familiar with batch (plus I'm not the best at explaining technical things).

The first non-comment line turns off the command echo, then if the first
parameter is equal to "Loop" it branches to whatever was specified as the
second parameter. For example, ... call %0 Loop unzip %%a will call itself
(the %0 parm) with the parameters Loop, unzip and %%a (supplied by the FOR
command). Program flow proceeds to the label :unzip and the file being
processed shows up as parameter %3. The first use will be to start a new
command shell to run the batch, but only if ZIP files are present. The
shell serves two purposes, first it ensures the batch will actually be able
to set variables without error (the /e:2000 part), second it causes the
batch to exit immediately if Ctrl-Break is pressed.

Now that a clean environment has been established the program calls itself
passing the name of every ZIP file using the FOR command ending up at the
:unzip label with the ZIP filename in %3. STRIPEXT (a program I made) is
then used to remove everything from "." on leaving a clean name to make a
directory with, which it does then unzips into it. This process is repeated
for every ZIP file.

After everything is unzipped control passes from the FOR command and
control branches to :movezips where CHOICE is used to ask the user if the
files should be moved to the archives directory. If not the second choice,
Y, control goes to :scanfiles otherwise the files are moved. A similar
question is asked about scanning the files, you'll have to modify the
choice of scanners to meet your needs, as written it'll only proclaim 'bad
command or filename' many times on any system but my own.

Menus for programs

The CHOICE command that comes with DOS 6 is handy for creating custom menus
for DOS programs as well as simple Yes/No questions. Here is a simple menu
for a few games...

@echo off
:menu
c:
cd\games
cls
echo    GAMES MENU
echo    ==========
echo.
echo    1 - Doom
echo    2 - Raptor
echo    3 - FlightSim
echo    4 - Lotus
echo.
echo    Q - Quit
choice /c:1234Q>nul
if errorlevel 5 goto done
if errorlevel 4 goto lotus
if errorlevel 3 goto flightsim
if errorlevel 2 goto raptor
if errorlevel 1 goto doom
echo CHOICE missing
goto done

:doom
cd doom
doom
goto menu

:raptor
cd raptor
rap
goto menu

:flightsim
d:
cd\fs4
fs4
goto menu

:lotus
cd lotusdrv
lotus
goto menu

:done

The idea is simple, set up initial conditions, in this case change to the
C: drive and the \games directory, print a menu using ECHO commands (use
echo. to print a blank line) then run the CHOICE command with the parameter
/c:1234Q (the valid choices) and redirect it to >nul so it doesn't mess up
the screen. After the user makes a decision, the errorlevel returned
depends on which one was picked, selecting Raptor for example returns
errorlevel 2. They are listed backwards because "if errorlevel 2 do
something" really means "if the errorlevel is 2 or greater do something".

ANSI codes can be used to spruce up menus like these, even decent
interfaces can be constructed in color using nothing but batch code.
Several menu utility programs are also available that are called from
batch.

Using menuing systems...

Several freeware, shareware and commercial menuing programs are available
that let you create nice-looking menus for your system. They're not as fun
as doing it entirely in batch but they can be more productive. A simple
menu program is CHOOSE, but it cannot handle very much text.

A more elaborate program is something called GO-MENU from an archive called
DOSVAR20 from Pinnacle Software. The shareware program was something for
manipulating strings (and was never even run) but GO-MENU.EXE is great.
Here is its help screen when run with "/?"...

      GO-MENU v1.21A -- Copyright (C) 1991,92 Pinnacle Software (Montreal)

       Purpose:   Displays a menu of up to 10 items
       Author:    Tim Campbell (Dial 514-345-9578; GEnie T.CAMPBELL11)
       Format:    GO-MENU [menu-file-name] [nnn] [save-file-name]
       Parms:     Specify nnn to save & read last selection
                  nnn is a save index from 0 to 255
                  save-file-name is the file that holds up to 256 saves
                  Program can continue if create or read of save file fails
       Defaults:  menu-file-name = GO-MENU.MNU
                  save-file-name = GO-MENU.SAV
       Menu File: Line 1    Menu heading
                  Line 2+   Menu lines
                  Note:     Lines starting with ; are ignored
       Returns:   1 - 10 depending on menu selection
                  200    if user pressed Esc in menu
                  250    for help request (this display)
                  255    for program error

Here is an example of how I use it, extracted from my master system
batch...

@echo off

--- stuff ---

:menu
c:
cd \
go-menu user.mnu
if errorlevel 11 goto exit
if errorlevel 10 goto boot1
if errorlevel 9 goto pic
if errorlevel 8 goto tape
if errorlevel 7 goto scanners
if errorlevel 6 goto editfiles
if errorlevel 5 goto sysinfo
if errorlevel 4 goto house
if errorlevel 3 goto setevars
if errorlevel 2 goto prompt
if errorlevel 1 goto windows
goto menu

:windows
win
goto menu

:prompt
command /e:2048
goto menu

--- more menus etc ---

This is the text file USER.MNU to define the menu text...

 My Computer System
    Run Windows
    Run DOS Prompt
    Set Environment
    HouseKeeping Utilities
    System Information
    Files / Environment
    Scanners
    Backup
    PIC Menu
    Reboot

I have no idea if GO-MENU is freeware, shareware or isn't even supposed to
be used but it does work well. You can probably find it in the SimTel
archives. Look for "DOSVAR20.ZIP". Many others are available, enough to
cause mental overload actually. Some of them can create very elaborate
screens once you master their convulted syntax (I haven't...).

Obtaining User Input

The CHOICE command is fine for asking limited-choice questions but it is
no-good for getting real strings like a filename. There are two approaches
that can be taken - use an external COM file like SENVAR.COM that directly
sets a variable entered by the user, or SETINVAR.COM that writes a
temporary batch that's called to set the variable. Or you can do it
completely in batch. I've seen a couple of variations to this technique,
one is contained in Dirk Van Deun's "Collection of Batch Techniques" file.
The one I've been using originated from a computer magazine (but that's not
where it really came from, just where I got it from), I've modified it to
work like a subroutine or a stand-alone batch.

@echo off
:: Original program from PC Magazine June 27, 1995 page 248
:: this version puts temps in C:\DOS dir and shortens var names
:: User input is returned in variable STR
:input
> C:\DOS\en#er.bat fc con nul /lb1 /n|date|find "1:"
> C:\DOS\enter.bat echo set str=
>>C:\DOS\enter.bat echo :loop
>>C:\DOS\enter.bat echo if not '%%str%%==' set str=%%str%% %%5
>>C:\DOS\enter.bat echo if '%%str%%==' set str=%%5
>>C:\DOS\enter.bat echo shift
>>C:\DOS\enter.bat echo if not '%%5==' goto loop
call en#er.bat
del C:\DOS\enter.bat
del C:\DOS\en#er.bat
if not '%return%==' goto %return%

Simply "call input.bat" (assuming that's what it's named) and the user
string is returned in the %str% variable. If this routine is included in
the batch program itself, set the return variable to call it like a
subroutine as in...

echo Enter filename...
set return=here
goto input
:here
echo You entered %str%
set return=
goto done

--- above input -----
:input
....
goto %return%
--- routine here ----

:done

When using batch input routines, do not enter redirection symbols or other
stuff that messes up DOS, especially < > and |.

Configuring your system

To use batch effectively you should check your CONFIG.SYS file for proper
settings. To use color you need something like:

DEVICE=C:\DOS\ANSI.SYS

or if UMB's are available (have a DOS=HIGH,UMB line) use:

DEVICEHIGH=C:\DOS\ANSI.SYS

If this line is not present add it with the other DEVICE's, might help if
it's first but that probably doesn't matter. When ANSI.SYS is active it
interprets escape codes that set screen colors, move the cursor and all
kinds of useful things. Type in HELP ANSI.SYS at a dos prompt for a
detailed list of the available commands.

Among the commands is the ability to re-define any key to output an entire
sequence of keys and commands upon typing the file. Files containing these
sequences are known as Key Macros or ANSI Bombs, depending on the commands
they contain. I use key macros to redefine my function keys to useful dos
commands. I am very used to hitting control-x instead of typing E X I T
Return. Just be aware of the potential problem and don't TYPE strange
files. Use something like LIST. Other versions of ANSI are available that
do not allow key redefinition if this makes you nervous. ThunderByte's
anti-virus driver will also prevent key redefinition after it's called,
just define what you want defined before calling TBDRIVER.

To prevent out-of-environment errors when running batch files you should
also have a SHELL statement in CONFIG.SYS to specify a larger-than-normal
environment, something like:

shell=c:\command.com /e:1024 /p

Some computers have COMMAND.COM only in the DOS directory, if there is no
COMMAND.COM in the root change 'c:\command.com' to 'c:\dos\command.com' or
wherever it is. If a 'set comspec=c:\command.com' line is present it should
match the path\filename given in the shell command.

---------------------------------------------------------------------------

Last modified Monday, April 29, 1996
