Batch has two control statements, if and for, plus goto and
call (Parameters and labels). The syntax here is
Microsoft’s, from its if
and for
pages.
Blocks
A pair of parentheses groups commands, over one line or several, so that an if,
else or for can take more than one. The ( must be where a command
can start and the ) must be where a command can start or at the end of the last command,
and both are plain characters in a quoted string.
if exist data.txt (
echo found
del data.txt
) else (
echo missing
)
- The
elsemust be on the same line as the)that closes theifblock, or on the same line as a one-line command (Microsoft: “You must use the else clause on the same line as the command after the if”). A)on a line of its own andelseon the next breaks it. - A block is read and expanded as a whole, so
%var%is not updated inside it; use delayed expansion. - A
)inside a block must be escaped (^)) or quoted if it is part of text, as inecho File^(s^); Microsoft’sechopage gives that rule. - Labels and
::comments inside a block are reported to be unreliable, and a::as the last line of a block gives an error. Userem.
if
| Form | True when |
|---|---|
if [not] string1==string2 command | The two strings are equal, character for character and case sensitive. Quotes count, so "a"==a is false |
if [not] errorlevel n command | The exit code of the last program is n or more (not equal). if not errorlevel 1 is “no error” |
if [not] exist name command | The file or folder exists. Wildcards are allowed and match files. A folder is tested with a trailing backslash or \nul in older Windows |
if [/i] string1 compareop string2 command | The comparison holds. /i ignores case. Needs command extensions |
if [not] defined variable command | The variable is set. Needs command extensions |
if [not] cmdextversion n command | The command extensions version is n or more; never true when extensions are off |
The comparison operators are EQU equal, NEQ not equal, LSS less
than, LEQ less than or equal, GTR greater than and GEQ greater
than or equal. They are not case sensitive as words. When both sides are made only of digits, the strings are converted to numbers
and compared as numbers (Microsoft), so 10 GTR 9 is true; otherwise they are compared as
strings, so 10 GTR 9a is false. /i works with the == form as well.
- Any of the forms may be followed by
elseand a command or block. ifcan be nested, and&,&&and||after the command belong to the command, not to the condition, soif a==a echo x & echo yruns both only when the condition is true. There is noandoror: nest theifs, or set a variable.- An empty or unset variable on one side breaks
if %a%==xintoif ==x, a syntax error. Quote both sides:if "%a%"=="x". - Special characters in an unquoted operand, such as a space,
&or a), end it early; quote it. - Microsoft: after
if defined, the variables%errorlevel%,%cmdcmdline%and%cmdextversion%are made available. - The
errorlevelform compares with the code left by the last program;%errorlevel%read inside a block shows the value from when the block was read.
if /i "%1"=="help" goto usage
if not defined LIB set LIB=C:\lib
if %errorlevel% geq 2 (echo failed) else (echo ok)
if exist "%~dp0data\*.txt" echo text files here
for
All the forms are for {%%|%}variable in (set) do command. Use %% in a batch
file and % at the prompt. The variable is one character, case sensitive, and any character
except 0 to 9 (so it is not mistaken for an argument); letters are the norm. No
more than 52 can be active at once. in and do are required words, not
parameters (Microsoft). The command can be a block.
| Form | The set | Each pass |
|---|---|---|
for %%v in (set) | Words separated by spaces, tabs, commas, semicolons or equal signs; wildcards * and ? match files | One word (one file) |
for /d %%v in (set) | Wildcards match folders only | One folder |
for /r [path] %%v in (set) | The set is run in path (default: the current folder) and every folder below it. A set of . lists only the folders | One file, with its full path |
for /l %%v in (start,step,end) | Three numbers; the step may be negative: (1,1,5) is 1 2 3 4 5, (5,-1,1) is 5 4 3 2 1 | One number, until it passes end |
for /f ["options"] %%v in (files) | One or more file names, read line by line | One token of a line |
for /f ["options"] %%v in ("string") | A literal string, parsed as one line | One token |
for /f ["options"] %%v in ('command') | The output of a command run by a child cmd.exe | One token of an output line |
for /f options
The options are in one quoted string, separated by spaces:
| Option | Meaning |
|---|---|
eol=c | One character that starts a comment line to skip (the default is ;) |
skip=n | Skip the first n lines of each file |
delims=xxx | The characters that separate tokens; the default is space and tab. delims= with nothing after it gives the whole line as one token |
tokens=x,y,m-n | Which tokens of a line to use: 2, 1,3, 2-4, or * for all the rest of the line. Each token beyond the first is put in the next letter after the variable (%%a, %%b, %%c…), as far as z. Without the option only the first token is used |
usebackq | Changes the quoting of the set: `command` in back quotes is a command, 'string' in single quotes is a literal string, and "file name" in double quotes is a file name with spaces. Without it, 'command' is a command and "string" is a literal string |
- Empty lines are skipped. A line with no token wanted gives no pass.
- In a
"string"set, the symbols\ & | > < ^are ordinary characters (Microsoft). - A command in a
for /fset that holds a pipe or redirection needs a caret before it:'dir ^| find "x"', because the set is parsed once for theforand again for the child interpreter. - The output of the command is captured in memory and parsed as if it were a file.
Variable modifiers
A for variable accepts the same ~ modifiers as the batch arguments:
%%~I (no quotes), %%~fI, %%~dI, %%~pI,
%%~nI, %%~xI, %%~sI, %%~aI, %%~tI,
%%~zI, %%~$PATH:I and the combinations %%~dpI,
%%~nxI, %%~fsI, %%~dp$PATH:I, %%~ftzaI. See the
table. A valid variable name ends the
%~ syntax, so an upper-case variable name keeps it readable (Microsoft).
rem every .txt file, each folder, and each line of a file
for %%f in (*.txt) do echo %%~nxf
for /d %%d in (C:\Users\*) do echo %%~nxd
for /r "C:\src" %%f in (*.c) do echo %%~ftzf
for /l %%n in (10,-2,0) do echo %%n
for /f "usebackq skip=1 tokens=1,2* delims=, " %%a in ("data file.csv") do echo %%a / %%b / %%c
for /f "delims=" %%l in ('type "%~f0" ^| find /c /v ""') do set lines=%%l
Loops without for
A counted or open loop is a label, a test and a goto:
set i=0
:again
set /a i+=1
echo Pass %i%
if %i% lss 5 goto again
Inside one parenthesised block this needs setlocal enabledelayedexpansion to see the
changing value. A for /l loop with a block runs the whole body in one pass and
goto out of it ends the loop.
Not described
Unknown
- Reference: the exact handling of labels and
::inside blocks, the caret rules inside afor /fcommand, and the old\nultest for a folder are from reported analysis, not Microsoft, and were not run oncmd.exefor this page. The defaulteol=;is from the interpreter’sfor /?help.