End

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

posted @ 2019-12-25 22:49  白乾涛  阅读(3526)  评论(0编辑  收藏  举报