曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4854|回复: 0
打印 上一主题 下一主题

[语法] for 循环

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
跳转到指定楼层
楼主
发表于 2012-5-8 20:09:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
for 循环用来对一组文件中的每一个文件执行某个特定命令。语法格式如下
[Plain Text] 纯文本查看 复制代码
FOR Parameter %variable IN (set) DO command [command-parameters]


Parameter 共有 4 个参数: /d , /l , /r , /f ,后面将对这 4 个参数做应用说明。

%variable  代表可替换的参数 。%variable 在命令行提示符下使用,%%variable 在批处理中中使用,大小写敏感。

(set) 指定一个或一组文件,可以使用通配符。也就是,FOR 会遍历 (set) 中指定的内容,每读取一项,就将其值赋给变量 %variable 。

command  指定对每个文件执行的命令。

command-parameters 为特定命令指定参数或命令行开关。

1. /d 表示操作的是目录
[Plain Text] 纯文本查看 复制代码
@echo off
for /d %%i in (*) do @echo %%i
pause
该脚本只会输出它所在的目录下的相关目录名(如果有的话)。

上面用的是通配符 *,也可以用通配符 ? ,问号通配符代表单个字符,比如我只想显示有 3 个名的文件夹,那么可以: for /d %%i in (???) do @echo %%i .


注意到上面打印目录名时,不会输出其子目录名,即不能递归。另外,这里的 (set) 是一个通配符,表示匹配每一个完整的目录名。一般情况下,我们常希望能递归到每个子目录,比如打印出当前目录下所有的目录名及其子目录名,此时就要用到另外一个参数 /r 了。

2. /r 表示递归操作
将 1 中的脚本修改如下:
[Plain Text] 纯文本查看 复制代码
@echo off
for /d /r %%i in (*) do @echo %%i
pause

上面的脚本比 1 中的增加了一个参数 /r ,那么输出的结果将是脚本所在目录下的所有目录名及其子目录名,比如:
E:\C\copyou
E:\C\copyou\copyou
E:\C\copyou\Debug
E:\C\copyou\ipch
E:\C\copyou\copyou\Debug
E:\C\copyou\ipch\copyou-60c8a289
请按任意键继续. . .

在上面的脚本中,我们还可以在 /r 后指定一个路径,这样它就可以该指定路径下的内容。如改成:
[Plain Text] 纯文本查看 复制代码
for /d /r D:/AMD %%i in (*) do @echo %%i


如果我们把上面的脚本中的 /d 参数去掉,那么就脚本就会获取所有指定目录及其子目录下的所有文件。然而 Windows 下的文件是以后缀名来区分的,因此我们可以用来查找某种特定的文件,比如 exe 文件,这样一来该脚本就显得实用多了:
[Plain Text] 纯文本查看 复制代码
@echo off
for /r D:/AMD %%i in (*.exe) do @echo %%i
pause

运行输出:
D:\AMD\AMD_Catalyst_12.1a_Preview_Win7_32-64\Setup.exe
D:\AMD\AMD_Catalyst_12.1a_Preview_Win7_32-64\Bin\ATISetup.exe
D:\AMD\AMD_Catalyst_12.1a_Preview_Win7_32-64\Bin\InstallManagerApp.exe
... ...
请按任意键继续. . .

3. /L 选项指定遍历范围
使用语法:
FOR /L %variable IN (start,step,end) DO command [command-parameters]

其中,(start,step,end) 中的 start 表示范围的开始,step 表示每次迭代的步进,end 表示范围之尾端。如下脚本所示:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /l %%i in (1,2,8) do @echo %%i 
pause

运行输出:
1
3
5
7
请按任意键继续. . .

当然,start 也可以大于 end,此时步进 step 为负数:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /l %%i in (15,-3,1) do @echo %%i 
pause

运行输出:
15
12
9
6
3
请按任意键继续. . .

该选项在实际应用中也是比较有用的,如批量建立文件夹,那么只要将上面的 @echo %%i 改成 md %%i ,这样就会依次建立其以 %%i 值为名的文件夹。

4. /f 选项
/f 选项有着稍微复杂点的应用,它主要用来操作文件及其内容。有 3 种使用方式:
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]

上面,file-set 表示一个或多个文件;string 表示字符串,command 表示命令;["options"] 是可选项。
按照帮助文件的说法为:
fileset 为一个或多个文件名。继续到 fileset 中的下一个文件之前,每份文件都被打开、读取并经过处理。处理包括读取文件,将其分成一行行的文字,然后将每行解析成零或更多的符号。然后用已找到的符号字符串变量值调用 For 循环以默认方式,/F 通过每个文件的每一行中分开的第一个空白符号。跳过空白行。您可通过指定可选 "options" 参数替代默认解析操作。这个带引号的字符串包括一个或多个指定不同解析选项的关键字。

上面所说的关键字先撇开不考虑,这样便可以由易到难,循序渐进的理解整个选项过程。现在假设脚本内容如下:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /f %%i in (1.txt) do echo %%i 
pause

上面的文件 1.txt  内容如下:
hellobat
hellowindows
helloshell

运行脚本输出:
hellobat
hellowindows
helloshell
请按任意键继续. . .

由此可见,1.txt 中的内容以行为单位依次被 for 调用读取到变量 %%i 中,然后打印输出。假如我们将 1.txt 的内容修改如下:
hello bat
hello windows
hello shell

那么再运行该脚本时会看到输出:
hello
hello
hello
请按任意键继续. . .

因为每行的内容有了空白符作为间隔,因此空白符其后的内容 FOR 就不能读取了。回头看帮助说明的那句话:“/F 通过每个文件的每一行中分开的第一个空白符号。跳过空白行。您可通过指定可选 "options" 参数替代默认解析操作。” 因此,这时 "options" 选项可以派上用场了,这里考虑 "delims" 和 "tokens" 这两个选项,帮助说明为:
delims=xxx      - 指分隔符集。这个替换了空格和跳格键的默认分隔符集。

tokens=x,y,m-n  - 指每行的哪一个符号被传递到每个迭代的 for 本身。这会导致额外变量名称的分配。m-n 格式为一个范围。通过 nth 符号指定 mth。如果符号字符串中的最后一个字符星号,那么额外的变量将在最后一个符号解析之后分配并接受行的保留文本。

因此,修改脚本如下:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /f "tokens=* delims= " %%i in (1.txt) do echo %%i 
pause

运行输出:
hello bat
hello windows
hello shell
请按任意键继续. . .

这下子输出正常了。如果我们只想输出文本中的第 2 列该如何做呢?答案是指定 tokens=2,修改上面脚本的命令为:for /f "tokens=2 delims= " %%i in (1.txt) do echo %%i ,再运行脚本时看到:
bat
windows
shell
请按任意键继续. . .

因此,往简单了说,delims 选项是指定每行文本的分隔符,而 tokens 实际上是由该分隔符所标识的列号。如果用过 Linux 的 awk 命令,那么这里 tokens 就相当于 '{print $2}' 中的 $2 标识的第二列。

再考察一个例子:
  1. @echo off
  2. FOR /F "delims=" %%i in ('net user') do @echo %%i
  3. pause
复制代码

运行输出:
\\BEYES 的用户帐户
-------------------------------------------------------------------------------
Administrator            beyes                    Guest
命令成功完成。

如果将上面的 "delims=" 去掉,那么只输出:
\\BEYES
-------------------------------------------------------------------------------
Administrator
命令成功完成。

添加 "delims=" 的目的是为了完整显示有空格作为间隔的行,如第一行 “\\BEYES 的用户帐户”中由空格分隔为 2 列;第 3 行“Administrator            beyes                    Guest”由空格分隔为 3 列。

实际上,delims 可以同时制定多个分隔符,比如:
  1. @echo off

  2. echo a b c d >>test.txt
  3. echo k,l,m,n >>test.txt
  4. echo o-p-q-r >>test.txt


  5. for /f "tokens=2-4 delims=,-" %%i in (test.txt) do echo %%i %%j %%k

  6. del test.txt

  7. pause
复制代码

运行输出:
l m n
b c d
请按任意键继续. . .

上面 delims 指定了两个分隔符(, 和 -)。


对于 tokens 还能指定范围这种情况还需要再做说明。假如现有一个测试脚本如下:
1 2 3 4 5 6 7
a b c d e f g
h i j k l m n

如果我们希望出第 2 列,第 3 列 和 第 4 列的内容那怎么办?看下面代码:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /f "tokens=2-4 delims= " %%i in (tmp.txt) do echo %%i %%j %%k
pause

运行输出:
2 3 4
b c d
i j k
请按任意键继续. . .

注意,如果要表示连续的几列,那么范围的表示法即为 "n-m",如上面的 "2-4" 。此外还需要注意的是 echo 语句中的 3 个变量 %%i, %%j, %%k ,这里的 %%j 和 %%k 是必须这么写的,因为前面使用了 %%i,所以现下读取 3 个列的内容,则用来存储这 3 个列内容的变量字母也必须相应递增(i --> j --> k,而不能跨越写成 %%i %%x %%z,这样是后面的 %%x 和 %%z 是识别不出来的,结果也只能打印为 %%x 和 %%z 的本身)。

如果要打印第 2 和 第 4 行,那么使用上面的命令改为:
[Plain Text] 纯文本查看 复制代码
for /f "tokens=2,4 delims= " %%i in (tmp.txt) do echo %%i %%j

注意,tokens 中的 2 和 4 是用逗号分开的。

如果想打印从第 2 列到最后一列的内容,那么命令改写成:
[Plain Text] 纯文本查看 复制代码
for /f "tokens=2,* delims= " %%i in (tmp.txt) do echo %%i %%j

这里,%%i 表示第 2 列;%%j 则表示剩下的所有列。

还有 skip 和 eol 这两个选项。skip 表示要忽略文件的前多少行;eol 表示当一行以什么符号开始就将其忽略(被认为是注释行)。下面举例说明,假设测试文本内容如下:
1 2 3 4 5 6 7
&a b c d e f g
h i j k l m n
&o p q r s t u
v w x y z A B

现在要忽略掉文本的前 2 行而输出余下的行,那么脚本代码为:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /f "skip=2 tokens=*" %%i in (tmp.txt) do echo %%i
pause

运行输出:
h i j k l m n
&o p q r s t u
v w x y z A B
请按任意键继续. . .

注意,这里要写上 tokens=* ,否则只会输出第 3 行到第 5 行的第 1 列内容,即第 3 行到第 5 行的开头那个字符。

忽略掉前面带有 & 符号的行:
[Plain Text] 纯文本查看 复制代码
@echo off 
for /f "eol=& tokens=*" %%i in (tmp.txt) do echo %%i
pause

运行输出:
1 2 3 4 5 6 7
h i j k l m n
v w x y z A B
请按任意键继续. . .


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-18 03:24 , Processed in 0.064934 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表