6.5. MS-DOS Batch Files
Most
Windows books treat batch files as if they were some kind of skeleton
in the closet or a crazy aunt you wouldn't want
anyone to meet. While it's true that batch files are
much less important than they were in DOS and earlier versions of
Windows, they can still provide useful functionality.The Windows Script Host (WSH), discussed in
Chapter 9, makes it easier to use much more
advanced scripting languages, such as
Visual Basic,
Perl,
PerlScript,
JavaScript, or
Python. But even with
WSH, batch files are not completely obsolete.A batch file
is an ASCII text file containing a series of commands, each on its
own line, that will be executed one line at a time. The filename of
the batch file becomes a command that can be executed at the Command
Prompt, from another batch file, or even run from a Windows Shortcut.Although any commands you can type at the command line can be used in
a batch file, several additional commands can be used only in a batch
file. These commands are used for loops, conditionals, and other
programming functions within the batch file and are explained in
detail later in this chapter.
6.5.1. Creating Batch Files
You can create
batch files with any text editor or word processor that can save
plain ASCII text files, such as
Notepad. In fact, by default, you can
right-click any batch file and select Edit to open that file in
Notepad.When naming a batch file, make sure you
don't use a name that is already used by a DOS
internal command (such as dir,
copy, or cd) or by a
.com or .exe file in your
search path. The reason for this is that when DOS executes programs,
it first looks for the .com extension and then
the .exe extension before finally executing a
file with the .bat extension. For instance, if
you have a file called work.exe, and you create
work.bat in the same directory, your batch file
will not execute unless you type the filename extension as well.
|
6.5.2. Some Rules of the Road
Here are the basics of batch file programming:
- Each command in a batch file must be on a separate line. The last
command line in the file should end with a carriage return. The
commands are the same as you'd type in succession at
the command prompt. - The name of the batch file itself is stored in the variable
%0. This allows you to do things like have a
temporary batch file that deletes itself when done. The name is
stored as it was typed at the command line, so if you had typed
myfile.bat, %0 would be
myfile.bat, but if you had typed
c:\batch\myfile, %0 would be
c:\batch\myfile. - A batch file run from the command prompt or by double-clicking on its
icon will open a command
prompt window while it is executing; however, a
batch file run from an existing command prompt window will run inside
that window. - Click the control menu and select Properties (see Section 6.1, earlier in this chapter,
for details) to control the default look and feel of the Command
Prompt window. To change these settings for an individual batch file,
create a Windows Shortcut to the batch file, right-click the new
shortcut, and select Properties. - The Properties sheet for the shortcut actually adds several options
not normally available through the control menu. For example,
ShortcutStart in allows
you to choose the initial working directory, and ShortcutRun allows you to have
the batch file run minimized. (Note that the option to have the
window close or remain open after it completes, found in some earlier
versions of Windows, is not present in Windows XP.)
You can stop a running batch file
by pressing Ctrl-Break or Ctrl-C; the following message will appear
in its DOS window: "Terminate batch
job (Y/N)?" Press Y to abort or N
to continue running the batch file.- By default, each command in a batch file is echoed to its DOS window.
To execute a command silently, precede it with an @ symbol.
Alternatively, you can turn command echo off by issuing @echo
off at the beginning of the batch file. - A batch file can contain any command that you can type at the command
prompt (e.g., anything described elsewhere in this chapter or in
Chapter 4). However, keep in mind that each
line in the batch file is executed sequentially, so there are a
couple of gotchas, especially when the batch file runs programs that
pop up a separate window. When you run a Windows program and it pops
up its own window, control returns immediately to the batch file and
the next line is executed. This
"race condition" is
unfortunately unavoidable with batch files; you'll
have to use a WSH script for this type of control (see Chapter 9). - You can store temporary data in your batch file using
environment
variables created with the set command. To use the
value of any variable with any other command or program, surround its
name with % symbols.
6.5.3. The "Why" and "When" of Using Batch Files
This section gives a few examples of
instances when you might want to use batch files.Batch files are used to automate repetitive tasks, but can be useful
for more than just issuing a sequence of commands. For example, type
the names of three applications in a batch file to have them all
opened in a single step. Or, write a one-line batch file that copies
a directory of files onto a removable drive; instead of performing a
copy manually every day before you go home from work, just
double-click the batch file icon and it will be done for you.Batch files are particularly powerful for creating and moving
files and directories.
For example, when starting a new project, an author might always want
to create the same directory structure and put some basic files into
each directory. Here's the kind of batch file you
might create for this kind of housekeeping:
@echo offCreate a new folder in the Explorer, and then drag and drop it onto
if "%1"==" goto skip
mkdir %1\figures
mkdir %1\sources
mkdir %1\old
copy c:\templates\mainfile.doc %1
copy c:\templates\other.doc %1
copy c:\templates\image.tif %1\figures
:skip
this batch file (or add the batch file to the SendTo menu).
Subdirectories called figures,
sources, and old will be
created inside, and three template files are copied into the new
directories. Voilàyou just saved about a minute of
clicking and dragging.The construct:
if "%1"==" go to skipis a useful error-checking technique. You can use an
if statement to test for null arguments (or other
similar conditions), and if encountered, either issue an error
message or simply quit. (This example will exit after jumping to the
:skip label, since there are no further commands
to be executed.)You can also use batch files to work around some of the limits of
Windows XP. For example, the Explorer doesn't let
you
print out a hardcopy
listing of the contents of a folder. You can do this from the command
line by typing:
dir > lpt1:But the following batch file does even better you can drag and
drop a folder icon onto it to get a printed directory listing:
@echo offYou could also replace lpt1: with something like
if "%1"==" goto skip
dir %1 > lpt1:
:skip
c:\windows\desktop\dir-list.txt to output the
directory listing to a text file instead, or construct a loop so that
the batch file could repeat itself automatically for multiple
directory name arguments.
6.5.4. Variables
Variables can be used in batch files. In
fact, a variable that is assigned in one batch file can be accessed
by a different batch file (in the same command prompt session), since
the command prompt environment is used to store all variables. See
"set", earlier in this
chapter, for more information on setting, modifying, reading, and
deleting variables from the environment.A batch file can take arguments such as filenames or options. Up to
nine arguments are stored in the variables %1
through %9. For example, the following line in a
batch file:
copy %1 %2would mean that the batch file would copy the filename specified in
the first argument to the name specified in the second argument. Use
this feature in conjunction with the if
statementfor example, to display a help screen when the
"user" includes the
/? option. The %* variable
returns a string with all arguments (e.g., %1 %2 %3 %4
%5...), which can be a convenient way to pass all a batch
file's arguments to another batch file or command.The following variable operators, a new feature in Windows XP, can
also be used with variables containing filenames. They
don't actually change the contents of the target
variable, but they do return an expanded version of it:%~ var
Expands %var, removing
any surrounding quotes.
%~f var
Expands %var to a fully
qualified path name (useful if
%var references a file
in the current directory).
%~d var
Expands %var to a drive
letter only.
%~p var
Expands %var to a path
only.
%~n var
Expands %var to a
filename only.
%~x var
Expands %var to a file
extension only.
%~s var
The expanded path contains short names only.
%~a var
Expands %var to file
attributes.
%~t var
Expands %var to the
date/time of the file.
%~z var
Expands %var to the
size of the file.
%~$ dir:var
Searches the directories listed in the dir
variable and expands
%var to the fully
qualified name of the first one found. If
dir is not defined, or the file is not
found by the search, then an empty string is returned. If you specify
path for dir, the
command search path will be used (see "path", earlier in this chapter).
These operators are most commonly used with command-line arguments;
for example, use %~z2
in a batch file to display the size of the file specified by
%2. These operators can be combined; for example,
%~nx1 expands %1 to the
filename and extension only, and %~ftza7 expands
%7 to a dir-like output line.
If the variable %var is
not defined or does not contain the filename of an existing file, an
empty string will be returned.
6.5.5. Additional Commands Used in Batch Files
The following list contains descriptions
of the commands that are used principally within batch files. These
can be used in conjunction with any of the commands listed earlier in
this chapter, as well as the filenames of any command prompt programs
or even Windows applications.
call |
Invoke a batch
file from within another batch file, returning control to the
original when the called file completes.
Syntax
call [filename] [arguments]
Description
The call command lets you invoke a batch file from
within another batch file and wait for it to finish before
continuing. Once the called file has completed its execution, the
control returns to the original batch file.
|
Specifies the filename of the batch file to call.
arguments
Specifies any command-line arguments to be passed to the target batch
file.
Examples
The following parent.bat calls
child.bat, and then returns the control back to
itself:parent.bat:
@echo offchild.bat:
cls
call child.bat First
set first=%inputvar%
call child.bat Second
set second=%inputvar%
echo You typed %first% and then you typed %second%
set /p inputvar=Please type the %1 option:In this example, parent.bat launches
echo Thank you.
child.bat twice, which illustrates how you can
write modular code in batch files. Child.bat
asks for input and then places what the user types into the
environment variable inputvar. When control is
returned to parent.bat, the variable
first stores the input so that
child.bat can be run again. At the end,
parent.bat spits out both variables.The next example illustrates how one of the batch
file's limitations can be overcome. The
if statement, discussed later in this chapter, is
only capable of executing a single command, but the following is a
simple workaround:parent.bat:
@echo offchild.bat:
for %%j in (1,2,3,4,5) do call child.bat
set /p inputvar=Please type option #%j%:
echo You typed %inputvar% - good for you.
choice |
in earlier versions of Windows is no longer supported in Windows XP.
The set command with the /p
option is a suitable replacement.
errorlevel |
for |
a specified command
any number of times.
Syntax
for [/d] %%variable in (set) do command [arguments]
for /r [path] %%variable in (set) do command [arguments]
for /l %%variable in (start,step,end) do command [arguments](in and do are not options, but
rather simply part of the syntax; if omitted, an error will occur.)
Description
Use this command to create loops in a batch file. A
for loop is a programming construct that allows
you to repeat a command for a list of items (such as filenames). You
specify an arbitrary variable name and a set of values to be iterated
through. For each value in the set, the command is repeated.The options used by for are the following:command [ arguments]
The command to execute or the program filename to run. This can be
anything you'd normally type at a command prompt;
arguments are the options, if any, to pass
to the command.
%% variable
A one-letter variable name that is assigned, one by one, to the
elements listed in set. Although
variable is treated like a standard
environment variable (see "set", earlier in this chapter),
it's name is case sensitive (%%j
is different than %%J) and can only be one letter
long. Note also the use of two preceding percent signs. If the
for command is issued directly from the command
prompt (and not from within a batch file), use only one percent sign
here.
set
The sequence of elements through which the for
command cycles. Elements are separated with spaces and can be files,
strings, or numbers. Wildcards can be used when specifying files. See
Examples, below, for details. Use the /l option
for the more traditional
start,step,end.
format.
/d
Instructs for to match against directory names
instead of filenames if set contains
wildcards. Can't be used with the
/l or /r options.
/l
Specifies that set takes the form of
start,step,end.,
allowing you to specify a range of numbers and an increment instead
of having to list each element. The /l parameter
allows you to mimic the more traditional usage of
for found in more advanced programming languages.
See Examples, below, for details.
/r [path]
Recursively executes command for each
directory and subdirectory in path. If
path is omitted, the current directory is
used. Without /r, files specified in
set only relate to the current directory.
The /r option instructs for to
"walk" the directory tree rooted at
path and repeat the entire loop in each
directory of the tree encountered. If set
is just a single period (.),
for will simply list all the directories in the
tree.
Examples
for can cycle through an array of strings:
for %%n in (rock paper scissors) do echo %%nCreate a set of numbered directories (e.g., ch1,
ch2, ch3,
ch4, and ch5):
for %%n in (1 2 3 4 5) do md ch%%nHere's an alternate way to accomplish the same
thing, using the /l option:
for /l %%n in (1,1,5) do md ch%%nHere, the first 1 represents the beginning number,
the second 1 represents the increment (or step),
and the 5 represents the end. Here are some more
examples of this syntax:
for /l %%n in (0,5,100) do echo %%nSince the for loop works only for a single command
for /l %%n in (100,-2,0) do echo %%n
(and it doesn't work well with
goto), you need to do something like this to run
multiple commands with for :
for %%f in (1 2 3 4 5) do call loop1.bat %%floop1.bat might then look like this:
echo done!
if not exist file%1 goto skipNote how the %%f variable is passed to
copy file%1 c:\backup
:skip
loop1.bat as a command-line parameter, and is
then referenced with %1.The set parameter can also contain filenames:
for %%j in (a.txt b.txt c.txt) do copy %%j a:The following statements are equivalent:
for %%x in (*.txt) do type %%xWhile the second example is simpler, it does illustrate a way to deal
type *.txt
with programs or commands that don't normally
support wildcards.List all the directories (with full paths) on your hard disk
for /r c:\ %%i in (.) do echo %%iCopy all .doc files in all subdirectories of
c:\Documents and Settings to drive
D :
for /r "c:\Documents and Settings" %%i in (*.doc) do copy %%i d:
Notes:
- When redirecting the output of a for loop to a file,
you'll want to use >>
(append to a file) rather than >. Otherwise,
you will save only the last iteration of the loop. - The commands executed by the for statement will be echoed to the
screen unless you issue the @echo off command
beforehand or precede command with
@. See "echo", earlier in this chapter,
for details. - The for command also supports the rather arcane
/f option; type for /? at the
command prompt for more information.
goto |
Branch to a
labeled line in a batch program.
Syntax
goto label
...
:label
GOTO :EOF
Description
goto is typically used with the
if statement to branch to a particular part of a
batch file, depending on the result of the condition or user
response.Label, any string of text (no spaces)
following a colon, marks the beginning of a section of a batch file
and represents a target for the goto command. Only
the first eight characters of label are
used; the labels pneumonia and
pneumonic are therefore equivalent. If you type
goto :eof (note the colon, not normally used
here), it will skip to the end of the batch file
(EOF=end of file).If your batch program doesn't contain the label you
specify after goto, the batch program stops and
displays the message "Label not
found." However, you can specify labels that
don't appear in goto commands.
Examples
Format a floppy disk in drive a: and display an
appropriate message of success or failure:
@echo off
format a:
if not errorlevel 1 goto skip
echo An error occurred during formatting.
exit
:skip
echo Successfully formatted the disk in drive a!
See Also
"if"
if |
Syntax
if [not] string1==string2 command [arguments]
if [/i] string1 compare-op string2 command [arguments]
if [not] exist filename command [arguments]
if [not] errorlevel n command [arguments]
Description
Conditional branching lets your batch file test to see whether a
condition is true, and if it is, instructs the batch file to execute
a command or continue execution at another location in the batch file
(via the goto command). The following options can
be used with the if command:command [ arguments]
The command to execute or the program filename to run. This can be
anything you'd normally type at a command prompt;
arguments are the options, if any, to pass
to the command.
not
Specifies that command should be carried
out only if the condition is false; not valid with
compare-op.
string1==string2
Specifies a true condition if the specified text strings match.
String1 and
string2 must be enclosed in quotation
marks or parenthesis.
string1 compare-op string2
Performs a more flexible comparison than
string1== string2,
shown above. The compare-op term can be
one of the following:
EQU
Equal
NEQ
Not equal
LSS
Less than
LEQ
Less than or equal
GTR
Greater than
GEQ
Greater than or equal
/i
Specifies a case-insensitive comparison; used only with
compare-op.
exist filename
Specifies a true condition if the specified file exists.
errorlevel n
Specifies a true condition if the previous command or program
returned an exit code equal to or greater than the number specified.
Zero typically means no error; other numbers depend on the command or
program.
Examples
Since batch files can accept parameters (stored in
%1, %2, %3,
and so on); the if statement is vital to
interpreting these parameters. The following statements might appear
at the beginning of such a batch file:
if "%1"==" echo You didn't specify a parameterThe following statements are equivalent:
if "%1"=="/?" goto help
if "%1"=="hullabalooza" goto doit
if not "%1"==" echo You must've typed something.The following batch file checks the current directory for the file
if "%1" NEQ " echo You must've typed something.
form.bat. If it finds it, the message
"It exists!" is displayed, and if
it doesn't, "The file
doesn't exist" is displayed:
@echo offWhen a program exits or a command completes, it returns an integer
if exist form.bat goto jump
goto skip
:jump
echo It exists!
pause
exit
:skip
echo The file doesn't exist.
pause
exit
value to the operating system called the
errorlevel. Typically,
errorlevel is zero (0) if the
operation was successful or a higher number if there was a problem.
The if errorlevel statement checks if the
errorlevel value is equal to or greater than a
specified number:
find /i "xp" c:\stuff\tips.txtNote that the if errorlevel statements are ordered
if errorlevel 2 goto error
if errorlevel 1 goto nomatch
if errorlevel 0 goto match
:match
echo A match was found!
goto end
:nomatch
echo Sorry, but a match wasn't found.
goto end
:error
echo Ack! An error has occurred!
:end
pause
so that higher numbers are checked first; if the order was reversed,
the first one (if errorlevel 0) would always
return true since the errorlevel is always greater
than or equal to zero.It's also important to account for the possibility
that none of the if statements will encounter a
true condition; in the example above, if all
errorlevel checks failed, execution would simply
continue onto the :match section.The if statement also supports
else, but the syntax is very strict.
else must be the first word on the line
immediately following the if statement, like this:
if exist %1 del %1Batch files in Windows XP also support if...else
else echo Sorry, %1 was not found
blocks, like this:
if exist %1 (The indenting here isn't necessary, but it does make
echo I'm about to delete %1. Are you sure?
pause
del %1
) else (
echo I couldn't find %1. To bad for you.
exit
)
the code easier to read. Note the opening and closing parentheses
used to enclose the blocks, and the fact that else
must be on the same line as the closing parenthesis of the first
block and the opening parenthesis of the second block.
See Also
"for", "goto"
pause |
Suspends processing of a batch program and
prompts the user to press any key to continue.
Description
Include the pause command whenever you want your
batch file to stop and wait for user input, giving the user a chance
to read the text on the screen, insert a floppy disk, or press Ctrl-C
to abort the batch file.The message "Press any key to
continue..." is automatically displayed whenever the
pause command is used; it is not affected by the
echo off statement.
Examples
Prompt the user to change disks in one of the drives in a batch
program:
@echo offWhen this batch file is executed, the following message will appear:
echo Insert next disk in drive A, and
pause
Insert next disk in drive A, andSomething like this is also common:
Press any key to continue ...
@echo off
echo Press Ctrl-C to cancel, or
pause
rem | Internal to: \Windows\command.com |
Insert comments
("remarks") into a batch file.
Lines beginning with rem will be ignored when the
batch file is executed.
Syntax
rem [comment]
Description
The comment can say whatever you want. It's a good
idea to put comments in your batch file so that others (including you
in the distant future) can figure out how it works.The rem command is also useful for disabling
commands. Just add rem right before the command to
disable it.
Examples
A batch file that uses remarks for explanations and to disable a
command:
@echo offThis example, if executed, would do absolutely nothing.
rem This batch program may one day change a directory.
rem But not until I remove the rem before the cd command.
rem It is called mydir.bat.
rem cd \batch\ch2
See Also
"echo"
shift |
Delete the
variable that holds the first command-line argument
(%1) and shifts over the remaining arguments.
Syntax
shift
Description
Use the shift command when you want to cycle
through all of the command-line arguments specified when the batch
file was run. When a shift statement is
encountered, the value stored in %2 is assigned to
%1, the value stored in %3 is
assigned to %2, and so on. The value stored in
%1 before the shift statement
is lost. This is particularly useful when processing loops.
Examples
In the following batch file, shift is used so that
each of the command-line options becomes option #1
(%1) for processing within the loop. The beauty is
that this works regardless of the number of arguments entered:
@echo offThe if statement tests for an empty argument
rem MTYPE.BAT
rem example: mtype foo.txt bar.txt *.bat
:loop
if "%1"==" exit
for %%f in (%1) do type %%f
shift
pause
goto loop
(meaning that shift has exhausted the supply of
arguments) and ends the loop when found.
Notes
- Normally, the number of command-line arguments is limited to nine
(%1 tHRough %9), but
shift makes it possible for a batch file to
accommodate more. - If you use a wildcard on the command line, it is passed to the batch
file as a single argument (e.g., *.*), which can be used as is. It
isn't expanded first, as with Unix shells, so you
can't pick it apart in the script and use each
matched filename separately.