BAT 批处理 for循环 迟环境变量
目录
FOR 命令使用总结
for /? > for_help.txt
- 在
批处理程序
中使用 FOR 命令时,指定变量请使用%%variable
而不要用%variable
。 - 变量名称是
区分大小写
的,所以%i
不同于%I
。
FOR
FOR %variable IN (set) DO command [command-parameters]
对一个 set 中的每一个元素(文件)执行某个特定命令。
%variable
指定一个单一字母
可替换的参数,可以使用但尽量不要使用数字(set)
指定一个集合,每个元素(文件)之间,可以用空格、跳格、逗号、分号或等号
分隔;可以使用通配符匹配文件command
指定对每个元素(文件)执行的命令command-parameters
为特定命令指定参数或命令行开关
for %%i in (1 2 3 4 5) do @echo %%i
for %%i in (c d e f g h i j k l m n o p q r s t u v w x y z) do if exist %%i: echo 存在分区%%i:
set /a num=0
for %%j in (%*) do set /a num+=1
echo 批处理文件调用的参数个数:%num%
for %%i in (*) do echo %%i %【当前目录下的所有文件,不包括目录】%
for %%i in (*.txt) do echo "%%i" %【当前目录下的所有.txt文件】%
for %%i in (??.txt) do echo "%%i" %【当前目录下的所有只用两个字符作为文件名的.txt文件】%
列出当前目录下各种文件的方法,最简单的还是用
dir
命令
FOR /D
FOR /D %variable IN (set) DO command [command-parameters]
D是指directory
,即为了处理文件夹。
有通配符
- 当 set 中包含有通配符
?
或*
时,它会匹配文件夹
,而不会匹配文件
- 不能匹配带隐藏属性的文件夹
- 它仅能匹配当前目录下的
第一级文件夹
,或是指定目录位置上的一级文件夹,而不能匹配更深路径下的子文件夹,即不能递归
。
for /d %%i in (*) do echo %%i %【当前目录下的所有子目录,不包括文件】%
for %%i in (*) do echo %%i %【当前目录下的所有文件,不包括目录】%
无通配符
当 set 中不包含任何的通配符时,它的作用和上面不带命令扩展时的语句无任何区别
。
- 不会排除掉带隐藏属性的文件夹
- 不会排除掉文件
- 总之就是和不带
/d
时无任何区别
for /d %%i in (test test.txt) do echo %%i
for %%i in (test test.txt) do echo %%i
/D /R 同时使用
for /d /r
其实是对/d
参数的扩展,/d
参数本身只能处理第一层文件夹,但是加上/r
参数后就可以处理所有的子文件夹。
- 在 for 有限的 4 个参数中,只有
/d
/r
可以一起使用(不分前后顺序) - 依然不能处理隐藏文件夹
For /d /r %%i in (*) do echo %%i
:: 显示当前目录下所有的文件夹(包括子文件夹),等价于【dir /ad /s /b】
FOR /R
FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
R 是指Recursive
,即递归
,换一个通俗一点的叫遍历文件夹
。
- 列举 set 及其之下的所有以
[drive:]path
为根的子目录,对这些文件夹都执行 command 语句 - 如果在
/R
后没有指定目录,则默认使用当前目录
- 由于
/R
语句是边列举路径边进行处理,所以在处理大量路径的时候,过程前期不会感到有停顿
set 是一个点号
如果 set 仅为一个点(.
)字符,则枚举该目录树
- 不能列举带隐藏属性的目录
- 列举出来的路径最后都带有
斜杠和点号
,例如D:\_test\.
D:\_test\bqt\.
for /r D:\_test\bqt %%i in (.) do echo %%i
for /r \_test\bqt %%j in (.) do echo %%j
for /r %%k in (.) do echo %%k
set 带通配符
列举[[drive:]path]
及其所有子目录下满足指定规则的文件
(不包括文件夹)。
for /r d:\_test %%i in (*.txt *bat*) do echo %%i
:: 列举指定目录下所有.txt结尾的文件,或所有文件名中包括bat的文件,不包括文件夹
set 不带点号或通配符
列举[[drive:]path]
及其所有的子目录
(不包括文件),都分别添加 set 的元素之后再显示出来
。
for /r D:\_test %%i in (包 青 天) do echo %%i
FOR /L
FOR /L %variable IN (start,step,end) DO command [command-parameters]
L是指loop
,即循环的意思。该集表示以增量形式从开始到结束的一个数字序列
- 所有的for语句,都可以看成是一种循环,只是在
/l
中,特指按照指定次数进行循环罢了 - start指起始值,step指步间距,end指终止值
- start、step和end都只能取整数,正负皆可
- 以上会遍历出所有满足以下条件的整数值:
k = start + n*step
,并且k <= end
,其中n=0,1,2,3...
必须保证能取到一个有效的数组序列
- 步间距step的值不能为0
- 当步间距step的值为正整数时,终止值end不能小于初始值start
- 当步间距step的值为负整数时,终止值end不能大于初始值start
for /L %%k in (0,1,3) do echo %%k %【0 1 2 3】%
for /L %%k in (0,-1,-3) do echo %%k %【0 -1 -2 -3】%
一般而言,for /l
语句可以换成goto
循环,但是,goto
循环并不一定能被for /l
语句替换掉。
- 当循环次数确定的时候,首选
for /l
语句 - 当循环次数不确定的时候,只能使用
goto
语句,因为这个时候需要用if
之类的条件语句来判断何时结束goto
跳转
FOR /F
FOR /F ["options"] %variable IN (file-set/"string"/'command') DO command [command-parameters]
基本用法
所有的对象,无论是文件、窗体、还是控件,在所有的非机器语言
看来,无外乎都是的文本信息,可以说,编程的很大一部分工作,都是在想方设法绞尽脑汁如何提取这些文本信息。
而for /f
就是被设计成专门用于解析文本的。
- 无论for语句做何种变化,它的执行过程仍然遵循基本的流程:依次处理每个元素,直到所有的元素都被处理为止
- 在
for /f
语句中,这里的元素是指文件中的每一行
,这是一条极为重要的规则
for /f %%i in (test.txt) do echo %%i %逐行打印指定文件的内容%
for /f %%i in (test.txt) do echo %%i&pause
delims
- 以指定的
符号列表
(符号只能是一个
字符/字母/数字/汉字)作为被处理的字符串的分隔符集
,切分字符串 - 默认只提取
第一节
的字符串作为最终结果 - 如果没有指定
delims=符号列表
这个开关,默认以空格键或跳格键
作为分隔符号 - 可以一次性指定多个分隔符号
for /f "delims= " %%i in (test.txt) do echo %%i
for /f "delims=12青天ab" %%i in (test.txt) do echo %%i %这里面的分割符有6个%
tokens
tokens=
后面一般跟的一个或多个是数字,每个数字之间用逗号
分隔- 数字的含义是:提取由
delims=
这一开关划分的第n
节字符串,划分的节是从1
开始算的 - 如果
tokens=
后面指定了多个数字,那么形式变量必须按照字母顺序定义,例如%%i
%%j
%%k
- 如果要提取的内容是
连续的
多节的话,那么连续的数字可以使用start-end
的形式替换 - 如果
tokens=
最后一个字符是星号,则后面的内容整体
被星号所表示的一个变量接收
for /f "delims=, tokens=2" %%i in (test.txt) do echo %%i
for /f "delims=, tokens=1,3" %%i in (test.txt) do echo %%i---%%j
for /f "delims=, tokens=1,2-4" %%i in (test.txt) do echo %%i---%%j---%%k---%%l
for /f "delims=, tokens=1-2,4,5-8" %%i in (test.txt) do echo %%i
for /f "delims=, tokens=1,*" %%i in (test.txt) do echo %%i---%%j
for /f "delims=, tokens=1,2-3,*" %%i in (test.txt) do echo %%i---%%j---%%k---%%l
skip
skip=n
,其中,n是一个正整数,表示在文件开始时要跳过的行数
for /f "skip=2" %%i in (test.txt) do echo %%i
eol
eol=
表示忽略以指定字符打头的行- 在指定字符的时候,
只能指定1个
,也可以不指定(即强制指定字符为空) for /f
语句是默认忽略以;
打头的行内容的(这种默认设置在delims=;
时无效),很多时候,我们可以充分利用这个特点,比如,在设计即将用for
读取的配置文件的时候,可以在注释文字的行首加上分号
for /f "eol=," %%i in (test.txt) do echo %%i
命令的 3 种形式
for /f %%i in (test.txt) do echo %%i %第2种形式:文件名%
for /f "delims=" %%i in ('dir .') do echo %%i %第2种形式:单引号+命令语句%
for /f "tokens=1,*" %%i in ("hello 包 青天 ") do echo %%i--%%j %第3种形式:双引号+字符串%
usebackq 的使用
如果文件名中含有空格
等特殊字符,例如test 1.txt
,该怎么办?
for /f %%i in (test 1.txt) do echo %%i %错误:找不到文件%
for /f %%i in ("test 1.txt") do echo %%i %错误:这是第3种形式,文件名被当做字符串处理了%
usebackq
是一个增强型参数,当使用了这个参数之后,原来的for
语句中第一个括号内的写法要做如下变动:
- 如果第一个括号里的对象是
文件名
的话,要用双引号"
括起来 - 如果第一个括号里的对象是一条
命令语句
的话,原来的单引号'
要改为后引号 - 如果第一个括号里的对象是
字符串
的话,原来的双引号"
要改为单引号'
for /f "usebackq" %%i in ("test 1.txt") do echo %%i
FOR /F %%i IN ('set') DO @echo %%i %枚举当前环境中的环境变量%
FOR /F "usebackq" %%i IN (`set`) DO @echo %%i
usebackq
除了在处理带空格的文件名
时会用到外,根本就没有其它的出场机会和存在价值。
迟环境变量的理解
变量延迟是批处理中一个十分重要的机制,它因预处理机制而生,用于复合语句,特别是大量使用于强大的for语句中,所以需要熟练地使用这一机制。
setlocal enabledelayedexpansion
语句的解释:
set
设置,local
本地(局部),enable
能够,delayed
延迟,expansion
扩展- 合起来就是:将变量设置为
局部变量
,并延迟环境变量的扩展行为
批处理的执行过程是怎样的?
自上而下,逐条执行
逐条
并不等同于逐行
,这个条
,是一条完整的语句
的意思,并不是指一行代码
什么样的语句才算一条完整的语句
?
- 在
非复合语句
中,如果该语句占据了一行
的位置,则该行代码为一条完整的语句 - 在
复合语句
中,整个复合语句是一条完整的语句
,而无论这个复合语句占用了多少行的位置 - 常见的复合语句有:
for
语句、if……else
语句、用符号&、||、&&、|
连接的语句,以及用括号
括起来的语句块
在代码逐条执行的过程中,批处理解释器
会对每条语句
做一些预处理工作
,这就是批处理中大名鼎鼎的预处理机制
!
预处理机制的基本过程:
- 首先,把
一条完整的语句
读入内存中,不管这条语句有多少行,它们都会被一起读入 - 然后,识别出哪些部分是命令关键字,哪些是开关、哪些是参数,哪些是变量引用……
- 如果代码语法有误,则给出错误提示或退出批处理环境
- 如果顺利通过,接下来,就把该条语句中所有被
引用的变量
及变量两边的百分号对
,用这条语句被读入内存之前
就已经赋予该变量的具体值
来替换…… - 当所有的预处理工作完成之后,批处理才会执行每条完整语句内部每个命令的原有功能
所以,如果命令语句中含有
变量引用
,并且某个变量的值在命令的执行过程中被改变了
,即使该条语句内部
的其他地方也用到了这个变量,也不会用最新的值去替换它们,因为某条语句在被预处理的时候,所有的变量引用都已经被替换成字符串常量了
。
解决的办法是:使用变量延迟扩展语句,即让变量的扩展行为延迟一下
,延迟之后,就可以让复合语句内部的变量实时感知到变量值的变化
,从而获取我们想要的值
变量扩展
是怎么一回事?
- 在许多可见的官方文档中,均将使用一对百分号闭合环境变量以完成对其值的替换行为,称之为
扩展(expansion)
- 这其实是一个
第一方
的概念,是从命令解释器
的角度进行称谓的,而从我们使用者
的角度来看,则可以将它看作是引用(Reference)
- 说得直白一点,所谓的变量扩展,实际上就是很简单的这么一件事情:
用具体的值去替换被引用的变量及紧贴在它左右的那对百分号
哪些场合需要使用变量延迟语句?
在复合语句内部,如果某个变量的值发生了改变,并且
改变后的值需要在复合语句内部的其他地方被用到
,那么就需要使用变量延迟语句。
延迟变量的扩展行为的两种方式:
- 在适当位置使用
setlocal enabledelayedexpansion
语句,然后把原本使用百分号对
闭合的变量引用改为使用感叹号对
来闭合;这种方式非常常见 - 在适当的位置使用
call
语句,即:在原来命令的前部加上call
命令,并把变量引用的单层百分号对
改为双层百分号对
;这种方式用得较少
@echo off & setlocal enabledelayedexpansion
set num=0 && echo !num!
@echo off
set num=0 && call echo %%num%%
2019-12-25
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/12099516.html