Section 14.4. Batch Files

Most Windows books treat batch files as though they are some kind of skeleton in the closet or a crazy aunt you wouldn't want anyone to meet. Although 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.

A batch file is a 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, executed 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.

14.4.1. Creating Batch Files

You can create batch files with any text editor or word processor that can save plain-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 Command Prompt 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 the Command Prompt 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.

You can create and execute batch files from the current directory or any directory in your search path, or by specifying their complete pathname, as with any other command. But if you're going to use batch files a lot, it makes sense to keep them all in one place. Create a directory called \Batch and add it to your search path. See "path," earlier in this chapter, for details.

14.4.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 those 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 such as 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 "Using the Command Line," 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, Shortcut Start In allows you to choose the initial working directory, and Shortcut Run allows you to have the batch file run minimized.

  • 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)?".

  • By default, each command in a batch file is echoed to the Command Prompt 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. 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.

  • 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.

14.4.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 they 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 off
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

Create a new folder in the Explorer, and then drag and drop it onto this batch file (or add the batch file to the SendTo menu). Subdirectories called figures, sources, and old will be created inside the target (when you drag and drop something onto a batch file, its name is put into the %1 variable), 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 skip

is 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 because there are no further commands to be executed.)

You can also use batch files to work around some of the limits of Windows Vista. 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 betteryou can drag and drop a folder icon onto it to get a printed directory listing:

@echo off
if "%1"=="" goto skip
dir %1 > lpt1:

If you don't have a parallel printer, you could also replace lpt1: with something such as c:\windows\desktop\dir-list.txt to output the directory listing to a text file instead (and then print it with notepad /p filename), or construct a loop so that the batch file could repeat itself automatically for multiple directory name arguments.

14.4.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), because 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 %2

means 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 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 pathname (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 if the file is not found by the search, 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.

14.4.5. Additional Commands Used in Batch Files

The following list contains descriptions of the commands that are used principally within batch files. You can use these 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.


Invoke a batch file from within another batch file, returning control to the original when the called file completes.


call [filename] [arguments]


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.

If you run another batch file from within a batch file without using call, the control will never be returned to the parent batch file when the child process is finished. The whole thing just quits. Of course, this fact can be put to use; for example, it helps to avoid recursion when a batch file calls itself.

The options for call are as follows:


Specifies the filename of the batch file to call


Specifies any command-line arguments to be passed to the target batch file


The following parent.bat calls child.bat, and then returns the control to itself:


@echo off
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:
echo Thank you.

In this example, parent.bat launches 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 capable of executing only a single command, but the following is a simple workaround:


@echo off
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.


  • call accepts labels as targets. For details, look in the help by typing help call at a command prompt.

choice: \windows\system32\choice.exe

Lets you select an item from a list of choices, then returns the index of that choice.


choice [/c choices] [/n] [/cs] [/t timeout /c choice] [/m text]


The options for choice are as follows:

/c choices

Specifies the list of choices to be created.


Hides the list of choices in the prompt. The message before the prompt is displayed, however, and the choices are still enabled, even though the list is hidden.


Enables case-sensitive choices. By default, choice is case-insensitive.

/t timeout

The number of seconds to pause before a default choice is made. Acceptable values are between 0 and 9999. If 0 is specified, there will be no pause and the default choice will be selected.

/D character

Specifies the default choice after timeout seconds. character must be in the set of choices specified by the /c option and must also specify timeout with /t.

/M text

Specifies the message to be displayed before the prompt. If it is not specified, choice displays only a prompt.


See "if," later in this chapter.


Repeat a specified command any number of times.


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 are simply part of the syntax; if omitted, an error will occur.)


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.

for uses the following options:

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), its name is case-sensitive (%%j is different from %%J) and can be only 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.


The sequence of elements through which the for command cycles. Elements are separated by spaces and can be files, strings, or numbers. Wildcards can be used when specifying files. See "Examples," discussed next, for details. Use the /l option for the more traditional start,step,end format.


Instructs for to match against directory names instead of filenames if set contains wildcards. Can't be used with the /l or /r option.


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," discussed next, 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 relate only 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.


for can cycle through an array of strings (remember, if you want to try these from the command line rather than in a batch file, use only one percent sign here):

for %%n in (rock paper scissors) do echo %%n

Create a set of numbered directories (e.g., ch1, ch2, ch3, ch4, and ch5):

for %%n in (1 2 3 4 5) do md ch%%n

Here's an alternate way to accomplish the same thing, using the /l option:

for /l %%n in (1,1,5) do md ch%%n

Here, 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 %%n
for /l %%n in (100,-2,0) do echo %%n

Because the for loop works only for a single command (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 %%f
echo done!

loop1.bat might then look like this:

if not exist file%1 goto skip
copy file%1 c:\backup

Note how the %%f variable is passed to 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 %%x
type *.txt

Although the second example is simpler, it does illustrate a way to deal 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 %%i

Copy all .doc files in all subdirectories of c:\Users\%USERNAME%\Documents to drive D:

for /r "c:\Users\%USERNAME%\Documents" %%i in (*.doc) do copy %%i d:


  • 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.


Branch to a labeled line in a batch program.


goto label


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. 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.


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 /b
echo Successfully formatted the disk in drive a!

See also



Execute a command if certain conditions are met.


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]


Conditional branching lets your batch file test to see whether a condition is true, and if it is, it instructs the batch file to execute a command or continue execution at another location in the batch file (via the goto command). You can use the following options 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.


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 parentheses.

string1 compare-op string2

Performs a more flexible comparison than string1==string2. The compare-op term can be one of the following:


Equal to


Not equal to


Less than


Less than or equal to


Greater than


Greater than or equal to


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 preceding 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.


Because 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 parameter
if "%1"=="/?" goto help
if "%1"=="hullabalooza" goto doit

The following statements are equivalent:

if not "%1"=="" echo You must've typed something.
if "%1" NEQ "" echo You must've typed something.

The following batch file checks the current directory for the file 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 off
if exist form.bat goto jump
goto skip
echo It exists!
exit /b
echo The file doesn't exist.
exit /b

When a program exits or a command completes, it returns an integer 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 whether the errorlevel value is equal to or greater than a specified number:

find /i "vista" c:\stuff\tips.txt
if errorlevel 2 goto error
if errorlevel 1 goto nomatch
if errorlevel 0 goto match
echo A match was found!
goto end
echo Sorry, but a match wasn't found.
goto end
echo Ack! An error has occurred!

Note that the if errorlevel statements are ordered so that higher numbers are checked first; if the order was reversed, the first one (if errorlevel 0) would always return true because 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 preceding example, 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 %1
else echo Sorry, %1 was not found

Batch files in Windows Vista also support if...else blocks, like this:

if exist %1 (
 echo I'm about to delete %1. Press Control-C to cancel
 del %1
) else (
 echo I couldn't find %1. Too bad for you.
 exit /b

The indenting here isn't necessary, but it does make 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" and "goto"


Suspends processing of a batch program and prompts the user to press any key to continue.


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.


Prompt the user to change disks in one of the drives in a batch program:

@echo off
echo Insert next disk in drive A, and

When this batch file is executed, the following message will appear:

Insert next disk in drive A, and
Press any key to continue ...

Something like this is also common:

@echo off
echo Press Ctrl-C to cancel, or


Insert comments ("remarks") into a batch file. Lines beginning with rem will be ignored when the batch file is executed.


rem [comment]


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.


A batch file that uses remarks for explanations and to disable a command:

@echo off
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

This example, if executed, would do absolutely nothing.

See also



Delete the variable that holds the first command-line argument (%1) and shifts over the remaining arguments.




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.


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 off
rem example: mtype foo.txt bar.txt *.bat
if "%1"=="" exit /b
for %%f in (%1) do type %%f
goto loop

The if statement tests for an empty argument (meaning that shift has exhausted the supply of arguments) and ends the loop when found.


  • 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 (fortunately, the FOR command does expand wildcards, which is why you can use *.bat as an argument to the batch file just shown).


Wait for a specified amount of time, or until a key is pressed, before performing the next command.


timeout /t [number] \nobreak


In addition to waiting a specified amount of time for a key to be pressed, timeout can also be told to ignore any key presses and wait the specified amount of time before performing the next command. You can use the following options with the timeout command:


Specifies the number of seconds to wait. The valid range is from -1 to 99,999 seconds. A value of -1 means to wait indefinitely for a key press.


Ignore key presses and wait the specified amount of time.


Wait 35 seconds before performing the next command:

timeout /t 35

Wait 50 seconds and ignore any pressed keys before performing the next command:

timeout /t 50 /nobreak


  • timeout is new to Windows Vista.

Part II: Nutshell Reference