批处理命令 For循环命令详解
批处理 for 命令详解
FOR 这条命令在批处理中通常被用来处理文本,但它的本事可不只这些——还有很多实用的功能等着我们去发掘。先看看它的基本格式(这里引用批处理中的格式,直接在命令行使用只需要一个 % 号):
FOR 参数 %%变量名 IN (相关文件或命令) DO 执行的命令
参数
/d、/l、/r、/f,具体作用下面通过例子说明。%%变量名
IN
(相关文件或命令)
do
执行的命令
也可以在 CMD 下输入 for /? 查看系统提供的帮助,对照一下:
FOR %%variable IN (set) DO command [command-parameters]
%%variable 指定一个单一字母可替换的参数。
(set) 指定一个或一组文件,可以使用通配符。
command 指定对每个文件执行的命令。
command-parameters 为特定命令指定参数或命令行开关。
现在开始逐项讲解每个参数的含义。
/d 参数
系统帮助格式:FOR /D %%variable IN (set) DO command
仅为目录
* 和 ?),将对与 Set 相匹配的每个目录(而不是目录中的文件组)执行指定的 Command。该参数主要用于目录搜索,不会搜索文件。看一个例子:
@echo off
for /d %%i in (*) do @echo %%i
pause
把这个 BAT 保存在 C 盘根目录执行,就会把 C 盘根目录下的全部目录名字打印出来,而文件名字一个也不会显示。
再来看一个:如果要打印当前目录下名字只有 1~3 个字母的目录:
@echo off
for /d %%i in (???) do @echo %%i
pause
如果当前目录下存在名字长度 1~3 个字母的目录,就会显示出来。
思考题:
@echo off
for /d %%i in (window?) do @echo %%i
pause
保存到 C 盘下执行,会显示什么呢?不妨自己试试看。
注意:/d 参数只能显示当前目录下的目录名字,这一点要牢记。
/r 参数
系统帮助格式:FOR /R [[drive:]path] %%variable IN (set) DO command
递归
/R 后没有指定目录,则认为当前目录。如果 Set 只是一个句点(.),则只枚举目录树。
之前提到 /d 只能显示当前路径下的目录名字,而 /r 比它强大得多——它可以把当前或指定路径下的文件名字全部读取(注意是文件名字)。看例子:
@echo off
for /r c:\ %%i in (*.exe) do @echo %%i
pause
把这个 BAT 保存到 D 盘任意位置执行,会看到它把 C 盘根目录以及每个子目录下面的所有 EXE 文件都列出来了。这里的 c:\ 就是搜索路径。
再来看一个:
@echo off
for /r %%i in (*.exe) do @echo %%i
pause
这次没有指定搜索路径,就会以当前目录为搜索路径。比如把 BAT 放在 d:\test 下执行,它会列出 d:\test 及其所有子目录下的 EXE 文件。
/l 参数
系统帮助格式:for /L %%Variable in (Start#,Step#,End#) do Command
迭代数值范围
/L 会通过比较 Start# 和 End# 来执行迭代——如果 Start# 小于 End#,就执行命令;如果迭代变量超过 End#,则命令解释程序退出此循环。也可以使用负的 Step# 递减。例如 (1,1,5) 生成序列 1 2 3 4 5,而 (5,-1,1) 生成序列 5 4 3 2 1。
举个例子:
@echo off
for /l %%i in (1,1,5) do @echo %%i
pause
执行后会打印 1 2 3 4 5 共五个数字。(1,1,5) 表示从 1 开始,每次加 1,直到 5 终止。
再看这个:
@echo off
for /l %%i in (1,1,5) do start cmd
pause
执行后会发现多了 5 个 CMD 窗口。如果把 (1,1,5) 改成 (1,1,65535),会打开 65535 个 CMD 窗口……不强制关机的话很难顶住。
当然,也可以把 start cmd 换成 md %%i,这样就会建立指定数量的目录,名字为 1~65535。
/f 参数(核心功能)
包含 /f 的 FOR 命令使用最多,也最为强大。用法如下:
FOR /F ["options"] %%i IN (file) DO command
FOR /F ["options"] %%i IN ("string") DO command
FOR /F ["options"] %%i IN ('command') DO command
这个参数主要用于处理文件和一些命令的输出结果。
file代表一个或多个文件string代表字符串command代表命令["options"]可选
对于 FOR /F %%i IN (file) DO command:file 为文件名。按照官方的说法,FOR 会依次将 file 中的文件打开,并且在处理下一个文件之前将每个文件读取到内存,按照每一行分成一个一个的元素,忽略空白的行。
假设文件 a.txt 中有如下内容:
第1行第1列 第1行第2列 第1行第3列
第2行第1列 第2行第2列 第2行第3列
第3行第1列 第3行第2列 第3行第3列
想显示 a.txt 中的内容,通常用 type a.txt,但 FOR 也可以做到:
for /f %%i in (a.txt) do echo %%i
这里会先打开 a.txt,读出所有内容,把每一行作为一个元素,生成集合:
{“第1行第1列 第1行第2列 第1行第3列”,
“第2行第1列 第2行第2列 第2行第3列”,
“第3行第1列 第3行第2列 第3行第3列”}
集合中只有 3 个元素,用 %%i 依次代替每个元素,然后执行 do 后面的命令。
为了加深理解,可以执行下面两个命令对比效果:
for /f %%i in (a.txt) do echo %%i ' 会显示 a.txt 内容
for %%i in (a.txt) do echo %%i ' 只显示 a.txt 这个名字,不读取内容
默认情况下,for /f 把每一行作为一个元素。但如果想把每一行再分解成更小的内容呢?FOR 提供了 delims 和 tokens 参数来实现。
delims 的作用
for /f "delims= " %%i in (a.txt) do echo %%i
显示结果为:
第1行第1列
第2行第1列
第3行第1列
因为 delims= 后面跟了一个空格,表示把每一行按空格分割,默认只取分割后的第一个元素。
tokens 的作用
delims 将每一行分成更小的元素后,由 tokens 控制取哪一个或哪几个。例如取第二列:
for /f "tokens=2 delims= " %%i in (a.txt) do echo %%i
执行结果:
第1行第2列
第2行第2列
第3行第2列
如果要显示第三列,就换成 tokens=3。同时 tokens 支持通配符 * 以及限定范围。如果要显示第二列和第三列,可以写成 tokens=2,3 或 tokens=2-3:
for /f "tokens=2,3 delims= " %%i in (a.txt) do echo %%i %%j
这里多了一个 %%j,因为 tokens 取两列,用 %%i 替换第二列,用 %%j 替换第三列(必须按英文字母顺序)。
执行结果为:
第1行第2列 第1行第3列
第2行第2列 第2行第3列
第3行第2列 第3行第3列
通配符 * 表示把这一行的剩余部分当作一个元素。例如:
for /f "tokens=* delims= " %%i in (a.txt) do echo %%i
执行结果与不加任何参数完全一致。
再看:
for /f "tokens=2,* delims= " %%i in (a.txt) do echo %%i %%j
执行结果:
第1行第2列 第1行第3列
第2行第2列 第2行第3列
第3行第2列 第3行第3列
这里 %%i 代替第二列,%%j 代替剩余部分。
还有两个简单的选项:
skip
eol
- :忽略文件的前 n 行。例如
skip=n
skip=2表示跳过前两行:
for /f "skip=2 tokens=*" %%i in (a.txt) do echo %%i
结果为:第3行第1列 第3行第2列 第3行第3列。如果不加 tokens=*,只会显示 第3行第1列。
- :指定行注释字符,以该字符开头的行会被忽略。例如 a.txt 内容变为:
eol=c
.第1行第1列 第1行第2列 第1行第3列
.第2行第1列 第2行第2列 第2行第3列
第3行第1列 第3行第2列 第3行第3列
执行:
for /f "eol=. tokens=*" %%i in (a.txt) do echo %%i
结果为:第3行第1列 第3行第2列 第3行第3列。

终极 dos 批处理循环命令详解
格式:FOR [参数] %%变量名 IN (相关文件或命令) DO 执行的命令
作用:对一个或一组文件、字符串或命令结果中的每一个对象执行特定命令,达到想要的结果。
注意:在批处理文件中使用 FOR 命令时,指定变量请使用 %%variable,不要用 %variable。变量名称区分大小写,所以 %i 不同于 %I。
关于参数:FOR 命令可以带参数或不带参数,带参数时支持 /d、/l、/r、/f。下面分别说明。
无参数时
格式:FOR %variable IN (set) DO command [command-parameters]
示例:
for %%i in (t*.*) do echo %%i '显示当前目录下与 t*.* 匹配的文件(只显示文件名,不显示路径)
for %%i in (d:\mydocuments\*.doc) do @echo %%i '显示 d:\mydocuments 目录下与 *.doc 匹配的文件
/d 参数
格式:FOR /D %variable IN (set) DO command [command-parameters]
用于目录搜索,不搜索文件,且只能显示当前目录下的目录名字(不会搜索子目录)。
示例:
for /d %%i in (c:\*) do echo %%i '显示 C 盘根目录下的所有目录
for /d %%i in (???) do echo %%i '显示当前目录下名字只有1~3个字母的目录
/r 参数
格式:FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
搜索指定路径及所有子目录中与 set 相符合的所有文件。
- 如果
set中包含通配符(?或*),则列举/R参数指定的目录及其所有子目录中匹配的文件。 - 如果
set是具体文件名(不含通配符),则枚举该目录树(列出该目录及其所有子目录),并在后面加上具体的文件名,不管该文件是否存在。
示例:
for /r c:\ %%i in (*.exe) do echo %%i '列出 C 盘所有子目录下的 EXE 文件
for /r c:\ %%i in (boot.ini) do echo %%i '枚举 C 盘所有目录(实际未必存在该文件)
for /r c:\ %%i in (boot.ini) do if exist %%i echo %%i '很好的搜索命令,只列出 boot.ini 存在的目录
/l 参数
格式:FOR /L %variable IN (start,step,end) DO command [command-parameters]
以增量形式从开始到结束的数字序列。
示例:
for /l %%i in (1,1,5) do @echo %%i '输出 1 2 3 4 5
for /l %%i in (1,2,10) do @echo %%i '输出 1 3 5 7 9
for /l %%i in (100,-20,1) do @echo %%i '输出 100 80 60 40 20
for /l %%i in (1,1,5) do start cmd '打开5个CMD窗口
for /l %%i in (1,1,5) do md %%i '建立1~5共5个文件夹
for /l %%i in (1,1,5) do rd /q %%i '删除1~5共5个文件夹
/f 参数(详细)
这个参数最复杂,选项也最多。简单说:for /f 可以分析文件内容、字符串内容或某命令输出的结果,并通过 options 得到想要的结果。
格式:
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
如果有 usebackq 选项:
FOR /F ["options"] %variable IN ("file-set") DO command [command-parameters]
FOR /F ["options"] %variable IN ('string') DO command [command-parameters]
FOR /F ["options"] %variable IN (`command`) DO command [command-parameters]
(注意:这里的反引号 ` 是键盘上数字1左面的键)
OPTION 关键字详解:
eol=c:指定行注释字符,例如eol=;表示忽略以分号开头的行。skip=n:跳过文件前 n 行。delims=xxx:指定分隔符集,替换默认的空格和 Tab。例如delims=,表示用逗号和空格作为分隔符。tokens=x,y,m-n:指定每行的哪些令牌(符号)被传递到 FOR 迭代。可以分配额外变量。如果最后一个字符是*,则额外的变量接收行中剩余的所有文本。例如tokens=2,3*会将第二个和第三个符号赋给两个变量,剩下的赋给第三个变量。usebackq:用于处理文件名或路径中含有空格的情况。不使用usebackq时:(file)表示文件,不能加引号;双引号表示字符串;单引号表示命令。使用usebackq时:(file)和("file")都表示文件(允许带空格的文件名);单引号表示字符串;反引号表示命令。
file-set
/F 传递每个文件每一行的第一个空白分隔符号,跳过空行。
%i
%j 和 %k 通过 tokens= 选项说明。最多可指定 26 个符号(字母 a~z 或 A~Z)。
系统提供的范例:
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k
说明:分析 myfile.txt 的每一行,eol=; 忽略分号开头的行;tokens=2,3* 将第二、三个符号传给 FOR 程序体;delims= , 用逗号和/或空格作分隔符;%i 取第二个符号,%j 取第三个符号,%k 取剩余部分。
自己动手的几个例子:
1. 分析文件:
FOR /F "eol=; tokens=1,2* delims=,- " %%i in (d:\test.txt) do echo %%i %%j %%k
2. 分析字符串:
for /f "tokens=1,2,3* delims=-, " %%i in ("aa bb,cc-dd ee") do echo %%i %%j %%k %%l
3. 分析命令输出(枚举环境变量):
FOR /F "tokens=1* delims==" %%i IN ('set') DO @echo [%%i----%%j]
如果使用了 usebackq,结果完全相同:
1. 分析文件:
FOR /F "usebackq eol=; tokens=1,2* delims=,- " %%i in ("d:\test.txt") do echo %%i %%j %%k
2. 分析字符串:
for /f "usebackq tokens=1,2,3* delims=-, " %%i in ('aa bb,cc-dd ee') do echo %%i %%j %%k %%l
3. 分析命令输出:
FOR /F "usebackq tokens=1* delims==" %%i IN (`set`) DO @echo [%%i----%%j]
FOR 命令中的变量
FOR 变量参照的替换已被增强。可以使用以下选项语法(以 %I 为例):
~I- 删除任何引号,扩展 %I%~fI- 将 %I 扩展到一个完全合格的路径名%~dI- 仅将 %I 扩展到一个驱动器号%~pI- 仅将 %I 扩展到一个路径%~nI- 仅将 %I 扩展到一个文件名%~xI- 仅将 %I 扩展到一个文件扩展名%~sI- 扩展的路径只含有短名%~aI- 将 %I 扩展到文件的文件属性%~tI- 将 %I 扩展到文件的日期/时间%~zI- 将 %I 扩展到文件的大小%~$PATH:I- 查找列在 PATH 环境变量中的目录,并将 %I 扩展到找到的第一个完全合格的名称。如果未定义环境变量或找不到文件,则扩展为空字符串
还可以组合修饰符获得多重结果:
%~dpI- 仅将 %I 扩展到一个驱动器号和路径%~nxI- 仅将 %I 扩展到一个文件名和扩展名%~fsI- 仅将 %I 扩展到一个带有短名的完整路径名%~dp$PATH:i- 查找 PATH 目录,并将 %I 扩展到找到的第一个驱动器号和路径%~ftzaI- 将 %I 扩展为类似 DIR 输出格式的行
注意:使用 ~ 语法时,必须用一个有效的 FOR 变量名终止。选取类似 %I 的大写变量名比较易读。
以下是一个综合示例,可以直接保存为 BAT 文件运行,观察变量扩展的效果:
@echo off
echo ---显示 "dir c:\boot.ini /b /ah"
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 不扩展变量 %%i
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~fI %%~fi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~dI %%~di
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~pI %%~pi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~nI %%~ni
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~xI %%~xi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~sI %%~si
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~aI %%~ai
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~tI %%~ti
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~zI %%~zi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~$PATH:I %%~$PATH:i
echo ---以下显示组合修饰符---
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~dpI %%~dpi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~nxI %%~nxi
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~fsI %%~fsI
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~dp$PATH:I %%~dp$PATH:i
for /f "delims==" %%i in ('dir c:\boot.ini /b /ah') do echo 扩展变量到~ftzaI %%~ftzai
echo.
echo ---显示 "dir C:\WINDOWS\system32\notepad.exe /b"
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 不扩展变量 %%i
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~fI %%~fi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~dI %%~di
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~pI %%~pi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~nI %%~ni
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~xI %%~xi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~sI %%~si
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~aI %%~ai
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~tI %%~ti
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~zI %%~zi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~$PATH:I %%~$PATH:i
echo ---以下显示组合修饰符---
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~dpI %%~dpi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~nxI %%~nxi
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~fsI %%~fsI
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~dp$PATH:I %%~dp$PATH:i
for /f "delims==" %%i in ('dir C:\WINDOWS\system32\notepad.exe /b') do echo 扩展变量到~ftzaI %%~ftzai
Pause
关于 ~I 删除引号的规则
- 若字符串首尾同时存在引号,则删除首尾的引号;
- 若字符串尾不存在引号,则删除字符串首的引号;
- 如果字符串中间存在引号,或者只在尾部存在引号,则不删除。
看一个测试:建立临时文件 temp.txt,内容如下
"1111
"2222"
3333"
"4444"44
"55"55"55
用下面的代码测试:
@echo off
echo ^"1111>temp.txt
echo "2222">>temp.txt
echo 3333^">>temp.txt
echo "4444"44>>temp.txt
echo ^"55"55"55>>temp.txt
FOR /F "delims=" %%i IN (temp.txt) DO echo %%~i
pause
del temp.txt
执行后 CMD 回显:
1111 '字符串前的引号被删除
2222 '首尾引号都被删除
3333" '前无引号,后面引号保留
4444"44 '前面引号删除,中间引号保留
55"55"55 '前面引号删除,中间引号保留
%~fI 示例
FOR /F "delims==" %%i IN ('dir /b') DO @echo %%~fi
pause
放在桌面执行,会显示 C:\Documents and Settings\Administrator\桌面\test.bat 这样的完整路径,而如果用 %%i 只显示文件名。
%~dI 示例
%~pI 示例
%~nI 示例
%~xI 示例
%~sI 示例
%~aI
%~tI
%~zI
注意:上面的例子中 "delims==" 可以改为 "delims="(不要分隔符)。
%~$PATH:I 示例
@echo off
FOR /F "delims=" %%i IN ("notepad.exe") DO echo %%~$PATH:i
pause
这条命令会在 PATH 环境变量指定的目录中搜索 notepad.exe,如果找到则打印其绝对路径,否则打印空字符串或错误信息。注意:这里的文件名需要用双引号括起来,并且不能使用中文字符的引号。