[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[原创] [分享]批处理命令for 另类用法

本帖最后由 CrLf 于 2014-4-29 00:54 编辑

一、十六进制转十进制
  1. ::常见方案
  2. set hex=4F
  3. set /a num=0x%hex%
  4. echo 十六进制数 %hex% 的十进制数为 %num%
复制代码
  1. ::for /l 方案
  2. set hex=4F
  3. for /l %%a in (0x%hex% 1 0x%hex%) do echo 十六进制数 %hex% 的十进制数为 %%a
复制代码
二、useback,你可以安息了
注:useback 不是笔误,它和 usebackq 其实没有区别。
应对字符串本身带有引号的情况:
  1. ::常见方案:
  2. set str="<test>"
  3. for /f useback %%a in ('%str%') do echo %%a
复制代码
  1. ::转义方案
  2. set str="<test>"
  3. for /f %%a in (^"%str%^") do echo %%a
复制代码
处理文件路径必须用引号的情况:
  1. ::常见方案
  2. set "file=%programfiles%\(te)&(st).txt"
  3. for /f "useback delims=" %%a in ("%file%") do echo %%a
复制代码
  1. ::首引号方案(勘误方案,原理见 8 楼,感谢 7 楼的指正与启迪):
  2. set "file=%programfiles%\(te)&(st).txt"
  3. for /f "delims=" %%a in ("%file%
  4. ) do echo %%a
  5. rem 如果%file% 中不含特殊字符,可以写成一行为:
  6. rem     for /f "delims=" %%a in (^"%file%) do echo %%a
复制代码
  1. ::上级路径方案
  2. set "file=%programfiles%\(te)&(st).txt"
  3. for /f "delims=" %%a in ("%file%\test"\..) do echo %%a
  4. rem 时灵时不灵,仅作参考...
复制代码
三、避免 for /f 从命令获取输入时,命令行参数首尾都有引号产生的错误处理字符串字符串本身带引号的情况:
  1. ::错误模拟(假定 %programfiles% 含空格)
  2. for /f %%a in ('"%programfiles%\winrar\rar.exe" v "1.rar"') do echo %%a
  3. rem 错误产生原因见附文
复制代码
  1. ::解决方案
  2. for /f %%a in ('^;"%programfiles%\winrar\rar.exe" v "1.rar"') do echo %%a
复制代码
四、显示 test.txt 中含有“测试”的行
  1. ::find 方案,直接,但是外部命令的效率欠佳
  2. find "测试"<test.txt
复制代码
  1. ::if+变量替换方案,效率和可控性好一些
  2. for /f "delims=" %%a in (test.txt) do (
  3.         set str=%%a
  4.         setlocal enabledelayedexpansion
  5.         if "!str:测试=!" neq "!str!" echo !str!
  6.         endlocal
  7. )
复制代码
  1. ::(感谢 powerbat 指出原纯 for 方案有盲点,现改为 for+if 方案)for+ if 方案,某些情况下是比较好的选择
  2. for /f "delims=" %%a in (test.txt) do (
  3.     for /f "delims=试" %%b in ("[%%a]") do (
  4.         for /f "tokens=2 delims=测" %%c in ("[%%b]") do if %%c==] echo %%a
  5.     )
  6. )
复制代码
五、for 参数的妙用
以往我们认为 delims 的内容无法含双引号(由于 ^ 无法左右 for 内部的引号匹配,所以 "delims="^" 没有效果),以及 eol 不能为空("eol=" 会将双引号设为分隔符),但是换个角度来思考即可迎刃而解:for 参数真的需要双引号吗?
  1. ::以双引号为分隔符
  2. for /f delims^=^" %%a in ("a"b"c") do echo 以 " 为分隔符的第一节为:%%a
复制代码
如此可以避免 for 解析参数时将 " 理解为参数分隔符,之所以要对 = 转义,是因为等号为 for 的默认分隔符,未通过转义符或双引号转义的等号在预处理时会被解释为空格
与 for 参数相关的讨论见:http://bbs.bathome.net/viewthread.php?tid=12500
  1. ::设置 eol 为 null
  2. for /f "delims="eol^= %%a in (";") do echo 设置 eol 为 null 的结果为:%%a
复制代码
经过验证,在以 "delims="eol^= 为参数 for /f 参数时 0x1~0x79 均不是 eol 的值,含 \x0 的行会被自动忽略故无法验证
至于 0x80 之后的扩展字符因为通用性问题用到的机会很少(见注)故未测试,因此可以视为此处 eol 等于 null。
注:eol 存在只取宽字符的首字节的特性,所以“eol=测”("测"的gbk码为B2E2)等效于“eol=悴”("悴"的gbk码为B2E3),故不建议设置 eol 为宽字符
附文:
【三】的例子中无论 rar.exe 存不存在,都能触发错误解析,先看一下 for /? 系统帮助中的这一部分:
    可以用 FOR /F 命令来分析命令的输出。方法是,将
括号之间的 filenameset 变成一个反括字符串。该字符串会
被当作命令行,传递到一个子 CMD.EXE,其输出会被捕获到
内存中,并被当作文件分析
。如以下例子所示:

正如帮助中所述,因为 for /f 从命令获取输入时,实际上是执行了:
  1. cmd /c "%programfiles%\winrar\rar.exe" v "1.rar"
复制代码

而在 cmd /? 的系统帮助中又提到:
如果指定了 /C 或 /K,则会将该开关之后的
命令行的剩余部分作为一个命令行处理,其中,会使用下列逻辑
处理引号(")字符:

   1.  如果符合下列所有条件,则会保留
       命令行上的引号字符:

       - 不带 /S 开关
       - 正好两个引号字符
       - 在两个引号字符之间无任何特殊字符,
         特殊字符指下列字符: &<>()@^|
       - 在两个引号字符之间至少有
         一个空格字符
       - 在两个引号字符之间的字符串是某个
         可执行文件的名称。

   2.  否则,老办法是看第一个字符
       是否是引号字符,如果是,则去掉首字符并
       删除命令行上最后一个引号,保留
       最后一个引号之后的所有文本。
从这里可以看出实例代码中给出的参数在不满足条件1 的同时又满足了条件2,因此预处理时将消除最外层引号各一,所以 cmd.exe 子进程所执行的是 %programfiles%\winrar\rar.exe" v "1.rar,很明显的,这不是我们所希望的,当然破解方法也很简单,只要不让双引号位于参数头或尾,这个隐患即不攻自破,解决方案中的 ^; 即是在传递给子进程的参数前附加一个 ; 符号,子进程认为它是分隔符而忽略,同时也使得条件2 不被满足,同理,也可以使用 ^=、^, 或 @ 来代替 ^;,原理大同小异。
2

评分人数

回复 2# applba


    并非华而不实的技巧,是实战中经常用到的
用 for /l 进行进制转换效率高于set /a,而且不需要临时变量
useback 是有名的 bug 多多,但有时候你不得不使用它(比如文件名含特殊字符的时候)
命令行参数首尾都有引号产生错误是经常有人碰到的
搜索字符或词语时,需要区分大小写或关键词含有 ~、!、*、= 等字符时,纯 for /f 方案就是不二选择,它的效率很高且比 if+变量替换方案 更通用
1

评分人数

TOP

本帖最后由 CrLf 于 2012-3-6 18:17 编辑

回复 5# powerbat


    确实忽略了这个可能性,感谢指正!
   稍作修改:
  1. for /f "delims=" %%a in (test.txt) do (
  2.     for /f "tokens=2 delims=测" %%b in ("[%%a]") do (
  3.         for /f "eol=] delims=试" %%c in ("%%b测") do (
  4.             for /f "tokens=2 delims=测" %%d in ("[%%c]") do echo %%a
  5.         )
  6.     )
  7. )
  8. rem 代码中的 # 处需使用不会出现在 test.txt 中的字符
复制代码
或使用更简便而通用的 for+if:
  1. for /f "delims=" %%a in (test.txt) do (
  2.     for /f "delims=试" %%b in ("[%%a]") do (
  3.         for /f "tokens=2 delims=测" %%c in ("[%%b]") do if %%c==] echo %%a
  4.     )
  5. )
  6. rem 不是纯 for 方案,但是 for 配合 if 更快,而且也没有什么盲点
复制代码
不过限于非遍历性质的代码思路,对存在多个测或多个试的行没办法进行有效判断

TOP

本帖最后由 CrLf 于 2012-3-17 19:22 编辑

回复 7# qzwqzw


    经测试,这一条确实是错误的,对不起!
   因为这用法在我印象中似乎有过成功的先例(可能记错了吧,惭愧),而且知道 for /f 是支持顺序从多个文件获取输入的,所以发帖之前没有再次进行验证

   【检讨】
    自从对预处理和各种命令的理解日深之后,渐渐不再对那些能够用个人理解去解读的代码进行测试了,直接结果就是,当个人理解有所偏差或者出现笔误的时候,写出的代码就是不可行的,因此发了很多误导人的帖子,实在抱歉了,各位坛友...


     【新的疑惑】
      另一方面,这个对于 for 的误会也揭开了一个新的问题,for /f 是如何区分字符串、文件和命令的?
    先假设 %file%=te st.txt
  1. echo;&echo 测试内容 = nul "%file%"
  2. for /f %%a in (nul "%file%") do echo %%a
  3. rem 试了一下 prn、con 等非文件设备似乎都被忽视了?我们用文件试一试
  4. pause
  5. echo;&echo 测试内容 = 文本1.txt 文本2.txt "%file%"
  6. for /f %%a in (文本1.txt 文本2.txt "%file%") do echo %%a
  7. rem 看来任意设备只要在 command 中打头,都能促使 for /f 从左到右遍历各个参数所对应的文件
  8. pause
复制代码
看来似乎可以总结出:“当 for /f 的 command 参数中以设备开头时,将按类似 %1、%2、%3... 的方式分别对其进行解析

但是还有一个现象:
  1. echo;&echo 测试内容 = "%file%" "%file%"
  2. for /f "delims=" %%a in ("%file%" "%file%") do echo %%a
  3. rem 这是常见的代码,此处 "%file%" "%file%" 将被输出为 %file%" "%file%
  4. pause
  5. echo;&echo 测试内容 = nul "%file%" "%file%"
  6. for /f "delims=" %%a in (nul "%file%" "%file%") do echo %%a
  7. rem 这是以设备开头的代码,此处 "%file%" "%file%" 将被输出为 %file%
  8. pause
复制代码
含 ' 的参数也具有同样的特性:
  1. for /f "delims=" %a in (nul 'pause' "test") do echo %a
  2. rem 终止于 'pause' 结束
复制代码
说明这个解析过程中如果发现字符串参数或命令行参数,则将其作为一行内容解析输出,并停止寻找下一参数
那么如果把 nul 和 "%file%" 出现的顺序反过来呢?
  1. echo;&echo 测试内容 = "%file%" nul
  2. for /f "delims=" %%a in ("%file%" nul) do echo %%a
  3. rem 此处为何仍提示“系统找不到文件 1 2.txt" nul。”呢?
  4. rem 也就是说可能是仅当参数首尾都为双引号时,才会将参数作为字符串解析
  5. pause
复制代码
作为上一个推论的证明:
  1. echo;&echo 测试内容 = ^^"%file%
  2. for /f "delims=" %%a in (^"%file%) do echo %%a
  3. rem 果然被解释为文件!
  4. pause
复制代码
也就是说,在不使用 useback 的情况下,当 for /f 排除分隔符后发现参数以 ' 或 " 打头,同时以 ' 或 " 结尾时将理解为是从字符串或命令获取输入。否则先理解为这些参数指的是文件,并把参数划分为 %1、%2、%3... 再分别对当前项进行判断其类型。

TOP

另外,1 楼补充了一个上级路径方案,但是遇到了些奇怪的问题...
  1. ::上级路径方案
  2. rem 本机测试:
  3. set "file=%programfiles%\(te)&(st).txt"
  4. echo TEXT>"%file%"
  5. for /f "delims=" %%a in ("%file%\t"\..) do echo %%a
  6. rem 输出[1]:TEXT
  7. rem 无误
  8. for /f "delims=" %%a in ("%file%\test"\..) do echo %%a
  9. rem 输出[1]:TEXT
  10. rem 输出[2]:系统找不到文件 춧咆。
  11. rem 正常输出 %file% 但也报错
复制代码
测试了好几中组合,结果失灵时不灵,似乎找不到规律

TOP

本帖最后由 CrLf 于 2012-3-19 14:43 编辑

回复 10# qzwqzw


确实比较曲折,因为以往没有意识到两点:
1、for /f 对参数的解析并不是简单判断首尾符号再 jmp 的,它会对参数进行分析再决定如何调用相应模块,这二者有点类似 %str% 与 !str! 的关系
2、字符串模块和命令输入模块调用完毕后会终止 for /f,所以他们可能是通过 jmp 调用的,而从文件读取输入时会将参数挨个解析,可能是用 call 的

另外,一直听人说 usebackq 问题很多,不知 usebackq 和 for /r 的 bug 是什么?可否举两个实例呢?

还有说道内存泄露,想起前两天看到旧帖中 zqz 回复的测试代码,稍微修改下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (0 1 8192) do (
  4.   set,=a!,!||(echo !,!&echo 长度为 %%a 个字符&pause)
  5. )
  6. pause
复制代码
链接:http://bbs.bathome.net/redirect. ... 8&fromuid=30406

这里让我搞不明白,变量名 , 明明存在于变量表中,为何会多出一个字节的容量,后来发现变量表里,!,! 变量末尾的 nul 消失了,并且跟着一串陌生的内容,以这段陌生内容为关键词搜索内存段,发现是紧跟在 ss:100 之前的内容(debug里看到的几个段寄存器是一样的,所以分不清是数据段还是堆栈段)。
可能因为 echo 命令错误退出的原因,有部分 !,! 的内容没有被填充为 nul,所以还能观察到 echo 的内容后丢失了 0A。
估计设置变量时,内存内容原本应该是 00(填充堆栈剩余内存) 变量内容(反序)=变量名(反序),以 , 为名设置变量时因为错误解析的原因把 00 挤没了(设置变量时是用的堆栈保存数据的吗?感觉有点像),cmd 将数据段字符串照搬到变量表时,却只以 00 为字符串结束的标志,所以 debug 可以看到溢出的内容,而用 set 或 echo 却只能看到变量 0~8192 字符长度的内容

TOP

回复 18# qzwqzw


变量名确实写错了,copy 测试文本时漏改一个。
xp 没有出现问题吗?win7 和 vista 下测试过,变量 !,! 确实能存放 8190 个字符长度的变量,而普通非分隔符 变量名则只能存放 8189 个,debug 部分见附文:
for /r 有问题是 10 楼说的呀...是否 for /f 之误?

附:
昨日的猜测有误,再次尝试 debug,全程如下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (0 1 8192) do (
  4.   set,=a!,!||(echo !,!&echo 长度为 %%a 个字符&debug&exit)
  5. )
  6. rem 将原测试代码改为达到上限时执行 debug,以便手动观察内存内容
复制代码
以下为进入 debug 后的键入的命令及输出:
  1. -d2cl2
  2. 1EEC:0020                                      51 07
复制代码
可知变量表的数据段地址为 0751
  1. -s751:0 lffff ",=aaa"
  2. 0751:0028
复制代码
得知 !,! 变量在变量表中始于 0028 偏移地址
  1. -h 28 1fff
  2. 2027  E029
复制代码
得知相对于 0028 偏移 1fff(即十进制 8191)的地址为 2027
  1. -d751:20
  2. 0751:0020  41 4E 44 2E 43 4F 4D 00-2C 3D 61 61 61 61 61 61   AND.COM.,=aaaaaa
  3. 0751:0030  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  4. 0751:0040  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  5. 0751:0050  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  6. 0751:0060  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  7. 0751:0070  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  8. 0751:0080  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  9. 0751:0090  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  10. -d751:2020
  11. 0751:2020  61 61 61 61 61 61 61 61-42 4C 41 53 54 45 52 3D   aaaaaaaaBLASTER=
  12. 0751:2030  41 32 32 30 20 49 35 20-44 31 20 50 33 33 30 20   A220 I5 D1 P330
  13. 0751:2040  54 33 00 00 01 00 43 3A-5C 57 49 4E 44 4F 57 53   T3....C:\WINDOWS
  14. 0751:2050  5C 53 59 53 54 45 4D 33-32 5C 44 45 42 55 47 2E   \SYSTEM32\DEBUG.
  15. 0751:2060  45 58 45 00 51 8C 56 1E-E8 2C 00 72 17 8B F7 E8   EXE.Q.V..,.r....
  16. 0751:2070  4D 00 00 5F 07 80 3C 00-75 01 4E E8 70 01 2B CE   M.._..<.u.N.p.+.
  17. 0751:2080  06 1F F3 A4 1F 5E C3 BE-4C 8C EB 03 BE 51 8C E8   .....^..L....Q..
  18. 0751:2090  05 00 72 F2 E9 9C 00 FC-E8 41 00 8E 06 1A 96 26   ..r......A.....&
复制代码
观察变量 !,! 头尾内容,发现末尾处的 00 丢失了,并且其后紧随着一串陌生的变量变量内容,于是在批处理中写入如下代码在内存中搜索,结果存于 s.txt
  1. (
  2. (
  3. for %%a in (0 1 2 3 4 5 6 7 8 9 a b c d e f) do @echo s %%a000:0 lffff "BLASTER=A220 I5 D1 P330"
  4. )
  5. echo q
  6. )|debug>s.txt
复制代码
s.txt 的内容:
  1. -s 0000:0 lffff "BLASTER=A220 I5 D1 P330"
  2. 0000:0C7D
  3. 0000:4522
  4. 0000:53F7
  5. 0000:59B7
  6. 0000:5A92
  7. 0000:5BA2
  8. 0000:A568
  9. 0000:B1D7
  10. 0000:B562
  11. -s 1000:0 lffff "BLASTER=A220 I5 D1 P330"
  12. -s 2000:0 lffff "BLASTER=A220 I5 D1 P330"
  13. -s 3000:0 lffff "BLASTER=A220 I5 D1 P330"
  14. -s 4000:0 lffff "BLASTER=A220 I5 D1 P330"
  15. -s 5000:0 lffff "BLASTER=A220 I5 D1 P330"
  16. -s 6000:0 lffff "BLASTER=A220 I5 D1 P330"
  17. -s 7000:0 lffff "BLASTER=A220 I5 D1 P330"
  18. -s 8000:0 lffff "BLASTER=A220 I5 D1 P330"
  19. -s 9000:0 lffff "BLASTER=A220 I5 D1 P330"
  20. 9000:5F02
  21. 9000:FFA6
  22. -s a000:0 lffff "BLASTER=A220 I5 D1 P330"
  23. -s b000:0 lffff "BLASTER=A220 I5 D1 P330"
  24. -s c000:0 lffff "BLASTER=A220 I5 D1 P330"
  25. -s d000:0 lffff "BLASTER=A220 I5 D1 P330"
  26. -s e000:0 lffff "BLASTER=A220 I5 D1 P330"
  27. -s f000:0 lffff "BLASTER=A220 I5 D1 P330"
  28. -q
复制代码
用 d 逐个查看,找到可疑的地址为 9000:5F02
  1. -d9000:5F02
  2. 9000:5F00        42 4C 41 53 54 45-52 3D 41 32 32 30 20 49     BLASTER=A220 I
  3. 9000:5F10  35 20 44 31 20 50 33 33-30 20 54 33 0D 74 2E 65   5 D1 P330 T3.t.e
  4. 9000:5F20  78 65 0D 61 61 61 61 61-61 61 61 61 61 61 61 61   xe.aaaaaaaaaaaaa
  5. 9000:5F30  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  6. 9000:5F40  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  7. 9000:5F50  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  8. 9000:5F60  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  9. 9000:5F70  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  10. 9000:5F80  B4 0E   
复制代码
果然有关联,但怎么有个 0d 呢?而且 BLASTER=A220  等内容既然是正序排列,为何位于 !,! 内容之前?
用 d9000:5e00 l140 继续观察前后内容(之前没发现,原来刚才那段段数据前面还有内容,汗,那就不是堆栈的原因了),发现这里似乎和变量表的内容不同
  1. -d9000:5e70 l120
  2. 9000:5E70  8C 16 30 00 2E 8E 16 57-22 BC A2 07 E8 80 31 8A   ..0....W".....1.
  3. 9000:5E80  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  4. 9000:5E90  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  5. 9000:5EA0  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  6. 9000:5EB0  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  7. 9000:5EC0  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  8. 9000:5ED0  61 61 61 61 61 61 61 61-61 61 61 61 00 20 20 20   aaaaaaaaaaaa.
  9. 9000:5EE0  20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20           .....
  10. 9000:5EF0  20 20 20 20 20 20 20 20-00 00 00 00 61 61 61 61           ....aaaa
  11. 9000:5F00  00 0D 42 4C 41 53 54 45-52 3D 41 32 32 30 20 49   ..BLASTER=A220 I
  12. 9000:5F10  35 20 44 31 20 50 33 33-30 20 54 33 0D 74 2E 65   5 D1 P330 T3.t.e
  13. 9000:5F20  78 65 0D 61 61 61 61 61-61 61 61 61 61 61 61 61   xe.aaaaaaaaaaaaa
  14. 9000:5F30  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  15. 9000:5F40  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  16. 9000:5F50  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  17. 9000:5F60  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  18. 9000:5F70  61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61   aaaaaaaaaaaaaaaa
  19. 9000:5F80  B4 0E CD 21 2E 8E 1E 1A-96 B8 FF FF 87 06 B4 02   ...!............
复制代码
得出的结果实在让我费解,为何这里也多了个 00 0d...
反复试验了一下,和我昨日的猜测不一样,似乎即使变量长度达不到 8190 也能看到同样的内存数据,那究竟是何处发生数据溢出的呢?
昨天没有想周全,所以当时的猜测不正确,看来仍然是个谜(对我来说)

TOP

回复 18# qzwqzw


    win7 下测试,这段代码显示 16 个 d(一个一行),似乎没有出现问题。
   对 useback 的 bug 向来是只闻其名不见其人(也许是用得少吧),刻意寻找也不知从何下手,看来 for /f 的幽灵很狡猾啊

TOP

回复 24# qzwqzw


    感觉似乎有道理,但是不知老兄得出的这些结论有何依据?还是仅仅为个人推测呢?没有冒犯的意思,只是想确保论点的“地基”是稳固可靠站得住脚的。

TOP

回复 26# qzwqzw


    大工程啊,建议开个专题来论证,最好能深入浅出讲解一番再附上具体的验证流程,这些溯本追源的命题无论是用于加深本质性的理解还是为日后重写 cmd 提供扎实的理论依据都很有必要

TOP

本帖最后由 CrLf 于 2012-4-2 00:51 编辑

回复 8# CrLf


zqz 给出了一个帖子的链接:http://www.bathome.net/viewthread.php?tid=3614
点进去一看,觉得很有意思,我这才知道 xp 和 win7 对于 for /f 中输入参数的解析方式是不同的,于是用代码测试看二者差异何在。在此不作长篇大论,概括性地总结一下个人理解:

首先,无论在 xp 还是 win7 下,for /f 的特性都是当参数以设备开头时将触发以类似 shift 的方式对参数挨个解析
  1. set str="bbs.bathome.net" "t e s t ?" "abc*"
  2. for /f "delims=" %%a in (nul %str%) do echo 第一节为:%%a
  3. rem win7 下,顺序解析将终止于用户所指定的最后一个参数或所遇见的第一个字符串参数再或者发生找不到指定文件的错误,所以 win7 下可以用非遍历的方法获取第一节的字符串——虽然比遍历方案方便,但是当然不如以双引号为分隔符来得直接,所以这是个没什么价值的方案
复制代码
  1. set str="bbs.bathome.net" "t e s t ?" "abc*"
  2. for /f "delims=" %%a in (nul %str:" "=" @"%) do echo %%a
  3. rem 而在 xp 下,顺序解析不会因为遇到字符串参数而终止,但是对下一个参数进行解析时,会诡异地吞掉该参数的首字符,所以此处要加个 @ 前缀以免双引号被吞出错,于是实现了 for /f 式的字符串循环,好处是不受 * 与 ? 的干扰,但是格式要求太严格,远不如以换行符为分隔符进行字符串循环来得方便有效,所以也是个没啥用处的技巧...
复制代码

TOP

回复 30# plp626


    这就是 win7 和 xp 的区别...

TOP

返回列表