Board logo

标题: [讨论]批处理for命令的参数和扩展特性 [打印本页]

作者: plp626    时间: 2011-5-25 19:00     标题: [讨论]批处理for命令的参数和扩展特性

本帖最后由 plp626 于 2011-6-14 19:25 编辑

引号也可作为for /f delims的分割符,只是由于大家思维定势忽略了:
http://bathome.net/thread-12395-1-2.html 6楼
  1. @echo off
  2. for /f tokens^=1*^ delims^=^" %%a in ("sd"z"vc") do echo %%b
  3. pause
复制代码
我对for的一些理解:
http://bathome.net/viewthread.ph ... romuid=353#pid80129 26楼
可以这样理解for的二次扩展特性:
for ~ cmd内部的一个类似call的子过程。。。
:FOR [/F | /R | /D |/L]  [option] %variable IN (<parameters>) DO ...

这个内部子过程有/l /r /d /f 四个开关,有共同的do in 关键字,一对括号;
有最多31个连续(以unicode编码存储)单字符名的内置变量,内置变量以%作为前缀标识;
(相对call,若不shift则为11个,分别为%0 %1 %2 。。。。 %9还有特别参数%*);
由于脚本中第一个%会被cmd预处理解析作为变量值开始扩展
所以要再用一个%对“%”转义(这点很像反斜杠\对自身的转义)

/f 开关有eol,skip,usebackq,delims,tokens,5个关键字,他们作为/f开关的 “第一个参数传递”

调用这个子过程的时候,参数分割符同call的参数分隔符(空格,制表符,逗号,分号,等号);

比如
  1. for /f "tokens=1-2 delims=:" %%a in ("abc:123") do echo %%a %%b
复制代码
我们把参数分割符空格改为;,=也可以正常解析:
  1. for=;/f=;;"tokens=1-2 delims=:";;%%a==in,,("abc:xy"),,=;do,=echo %%a %%b
复制代码
更新[2011-6-14]
内置变量名(统一以unicode编码存储)以%作为前缀标识,最多支持连续31个单字符;
  1. :: cmd命令行下粘贴如下代码
  2. :: "老" 到 "耣" 的unicode编码(连续地)为 "8001" 到 "8023"
  3. set ss=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
  4. for /f "tokens=1-31" %老 in ("%ss%")do @echo %老 %耂 %考 %耄 %者 %耆 %耇 %耈 %耉 %耊 %耋 %而 %耍 %耎 %耏 %耐 %耑 %耒 %耓 %耔 %耕 %耖 %耗 %耘 %耙 %耚 %耛 %耜 %耝 %耞 %耟 %耠 %耡 %耢 %耣
复制代码

作者: Bearxy    时间: 2011-5-25 19:05

白天的时候就看到了,不过一直没理解他转义符号的意思。
就干脆在这等待你们讨论了,每次plp626一出来唇枪舌战,总能收获不少东西。哈
作者: plp626    时间: 2011-5-25 19:28

但是有一点我没明白,for 中,^是怎么对空格进行转义的;

call中^为什么不行,为什么call会对字符的^加倍扩展一次。
作者: batman    时间: 2011-5-25 19:30

本帖最后由 batman 于 2011-5-26 22:22 编辑

个人认为/f开关是for所有开关中最重要的一个,对于新手甚至部分老手要掌握这个/f开关的所有参数及其用法是有一定难度的。。。

关于eol,usebackq,skip,tokens,delims这五个/f开关下的参数,记得cn-dos的9527有一篇贴子讲解得很是透彻,只可惜现在联盟不在了。。。

所幸jm著有批处理for从入门到精通的专门教程http://bbs.bathome.net/thread-2189-1-1.html,教程中对for命令进行了深入浅出的讲解并辅以大量的代码和实例加以论证,建议大家在加入此贴讨论之前先看篇教程。。。

在这里,本人只想提醒广大的新手在书写for /f语句时,参数顺序应为"eol= usbackq skip= tokens= delims=",特别是eol和delims参数最好(先前错误地写为必须)一个在最前一个在最后,至于为什么,大家可以思考一下了。。。
作者: namejm    时间: 2011-5-25 20:16

以引号作为分隔符确实是批处理研究中的一大突破
进而引发了对参数分隔机制的探讨
能解决很多实用的问题
那个帖子应该加精
至少是高亮
这样才能引起更多人的注意
作者: applba    时间: 2011-5-25 20:58

本帖最后由 applba 于 2011-5-25 21:20 编辑

我在补充一点,for /f的各个option之间的空格可以省略。不知道火星了吗?

::普通符号做分隔符
for /f "skip=1 tokens=3,4 delims=<>"
for /f "skip=1tokens=3,4delims=<>"

::引号做分隔符
for /f tokens^=1-3^ delims^=^"
for /f tokens^=1-3delims^=^"
作者: plp626    时间: 2011-5-25 21:08

楼上,很好!
  1. for /f eol^=^;tokens^=1-3delims^=+ %a in ("5678+678+78")do echo %a %b %c
复制代码
在for之前,我一直认为空格本身就不能通过^转义的;
为什么在for中就是例外?
原来,^对空格转义又是我理解上的“多虑”;
这样基本可以把for的参数分割符和call参数分割统一起来;
=========================
但是这里有一点未明:
既然tokens,deliims这些关键字作为/f开关的第一参数,为什么在引号内空格又不能省略?
作者: plp626    时间: 2011-5-25 21:12

又是思维定势:
原来空格一直都是我们的“多虑”
  1. for /f "eol=;tokens=1-3delims=+" %a in ("5678+678+78")do echo %a %b %c
复制代码

作者: caruko    时间: 2011-5-25 21:47

原来把 options 的=" 转义,就可以省略"",从而做到使用"做分隔符,又学到一招。
作者: CrLf    时间: 2011-5-25 22:58

看来for真的是个函数了,当初我就在纠结将for看成语块的时候,in前头的部分该理解成什么呢?现在用函数的观点来看,虽然“函数”是个比较万金油的概念,但确实比“语块”的说法更准确
作者: batman    时间: 2011-5-26 08:23

个人不建议省去for/f各个参数间的空格,代码除了简洁还要讲究可读啊。。。
作者: applba    时间: 2011-5-26 10:41

本帖最后由 applba 于 2011-5-26 10:42 编辑

继续补充,for /f "option" %%a in (set)
如果set中没有使用双引号时(但可能使用了单引号、反引号)出现特殊符号是需要使用^转义符号的。
  1. @ECHO OFF
  2. ECHO.
  3. SETLOCAL ENABLEDELAYEDEXPANSION
  4. :: Use WMIC to retrieve date and time
  5. FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
  6. IF NOT "%%~F"=="" (
  7. SET /A SortDate = 10000 * %%F + 100 * %%D + %%A
  8. SET /A SortTime = 10000 * %%B + 100 * %%C + %%E
  9. SET SortTime=0000000!SortTime!
  10. SET SortTime=!SortTime:~-6!
  11. )
  12. )
  13. SET Sort
  14. pause
复制代码
上面的例子中转义了逗号和管道符号。
作者: Hello123World    时间: 2011-5-26 15:39

6,11楼的话可以结合来看,for /f 各个参数之间的空格可以省略,但为了程序的可读性最好别省略。
作者: plp626    时间: 2011-5-26 16:27

本帖最后由 plp626 于 2011-5-26 16:36 编辑

12# applba

如果从call参数分隔符的角度去理解for /f 的第一参数(skip,delims那些) 和第二参数列表(括号里面的那些)
便不难理解为什么('命令')在“命令”含有逗号时要转义,因为它被当做参数分隔符解析为空了,

当括号里面有|,&,<,>这些特殊符号时为什么要用^转义这个也不难理解了

试想下call:标签 /f 参数1 内置变量 in (参数列表) do 。。。
当这个标签后面所跟的参数列表中出现|,<>,&这些特殊符号时,它会把这些特殊符号后面的字符串作为命令或其他东西解析了,参数列表被截断,而使得括号不能匹配,do关键字找不到,于是for报错了;
=========================
解决此两问题的办法我们除了用^转义|<>&还有参数分隔符外,也可以用双引号来统一解决:

for /f "选项" %%a in ('命令')do 命令 ---->>  for /f "选项" %%a in ('"命令"')do 命令
作者: CrLf    时间: 2011-5-26 16:41

本帖最后由 zm900612 于 2011-5-26 16:44 编辑

草就一个模型,就事论事,不考虑useback等因素,还有一些不用for的情况下不好处理的东西也一笔带过,比如tokens
  1. @echo off
  2. call :for /f "tokens=1* delims=:" %%a in ("%time%") do echo %%b
  3. pause&exit
  4. :for
  5. if %1==/f goto /f
  6. ...
  7. :/f
  8. set test=%2
  9. if "%test:~2%" neq "" set tokens=1* &set delims=: &shift /2
  10. set start=%2
  11. ...
  12. shift /3
  13. if "%~3" neq "%3" goto var
  14. if "%~3" leq " " goto command
  15. goto file
  16. ...
  17. :var
  18. set tmp=%~3
  19. setlocal enabledelayedexpansion
  20. set %%b=!tmp:*:=!
  21. echo !%%b!
  22. endlocal
  23. exit /b
复制代码

作者: CrLf    时间: 2011-5-26 17:38

我在想,如果for是个函数的话,它大概分为几大子函数:无开关、/f、/l、/r、/d
而仔细回想一下,发现只要有无开关的for作为基础,就能降低其他几个开关实现的难度。
最有代表性的是for /l和for /f,举个例子
for /l %%a in (1 2 10) do echo %%a
::在这个(1 2 10)中,若不用变量通配替换,如何区分初始值、步数和终止点呢?若用for %%a in (1 2 10)...来判断呢?区分参数的工作一下轻松了许多

for /f "tokens=1* delims=:" %%a in ("123:345") do echo %%b
::for在这里如何去分别设置tokens=1* delims=:呢?我想,如果把无开关的for当成基石,那又降低了实现门槛:for %%a in (tokens^=1* delims^= do set %%a,值得一提的是,我原以为applda兄的那段代码之所以不需要加空格,是因为cmd在预处理时将参数划分好再加上空格(就像对重定向干的事一样),但是后来实验证明并非如此,对参数的划分是for命令(函数)自发的,仔细想想这也有道理,毕竟在cmd中,"tokens=1* delims=:"是以%2的形式传递给for命令(函数),cmd不会去解释参数中的参数,因为那在除了for以外的环境下都将是好心办坏事,所以for函数就和我们平时编写的函数一样,自己动手丰衣足食
作者: applba    时间: 2011-5-26 18:05

16# zm900612

for确实是一个特别的命令,有一定的解释功能。
作者: CrLf    时间: 2011-5-26 19:16

本帖最后由 zm900612 于 2011-5-26 19:55 编辑

引申话题:
既然for是函数,那别的内部命令又是什么呢?
看来也是函数咯?如果这个说法成立,那其他内部命令和for和if命令之间的区别是什么呢?

其实现在想来,完全把for和if当成函数的观点也有一点瑕疵,我举个例子:
  1. call for %%%%a in ("123") do echo %%%%a
  2. call if exist %0 echo 123
  3. pause
复制代码
显示的是“'XX'不是内部或外部命令,也不是可运行的程序或批处理文件。”,而别的命令则不存在此问题,这是不是说明cmd中其实并不直接存在for这个模块呢?
作者: zqz0012005    时间: 2011-5-26 19:24

把以前的东西帖出来,先啥都不说,你们自己看,仔细看。(可怜以前没人参与讨论)
  1. -> type for.c
  2. #include <stdio.h>
  3. int main(int argc, char *argv[])
  4. {
  5.     int i;
  6.     for(i=0;i<argc;i++)printf("argv[%d]: `%s`\n", i, argv[i]);
  7.     return 0;
  8. }
  9. -> gcc -o for.exe for.c
  10. -> for.exe /f tokens^=1-3^ delims^=^" %a in ("a"b"c") do echo %a-%b-%c
  11. argv[0]: `for.exe`
  12. argv[1]: `/f`
  13. argv[2]: `tokens=1-3`
  14. argv[3]: `delims= %a in (abc) do echo %a-%b-%c`
  15. -> type for.bat
  16. @for.exe /f tokens^=1-3^ delims^=^" %%a in ("a"b"c") do echo %%a-%%b-%%c
  17. -> for.bat
  18. argv[0]: `for.exe`
  19. argv[1]: `/f`
  20. argv[2]: `tokens=1-3`
  21. argv[3]: `delims= %a in (abc) do echo %a-%b-%c`
  22. -> for.exe tokens^=1-3
  23. argv[0]: `for.exe`
  24. argv[1]: `tokens=1-3`
  25. -> test.bat tokens^=1-3
  26. %0: `test.bat`
  27. %1: `tokens`
  28. %2: `1-3`
复制代码

作者: CrLf    时间: 2011-5-26 19:27

楼上貌似是for的模型?
可惜我不懂编程,只能大概地猜下
作者: zqz0012005    时间: 2011-5-26 19:36

不是说for和if是“关键字”吗?难道是微软内部泄露出来的?
  1. -> type test.bat
  2. @prompt -$G$S
  3. echo a;echo
  4. for %%a in (a;echo) do echo a;echo
  5. echo for %%a in (a;echo) do echo a;echo
  6. rem if a;echo==a;echo echo a;echo
  7. if a==a;echo echo a;echo
  8. echo if a;echo==a;echo echo a;echo
  9. @echo\&pause
  10. -> test.bat
  11. -> echo a;echo
  12. a;echo
  13. -> for %a in (a echo) do echo a;echo
  14. -> echo a;echo
  15. a;echo
  16. -> echo a;echo
  17. a;echo
  18. -> echo for %a in (a;echo) do echo a;echo
  19. for %a in (a;echo) do echo a;echo
  20. -> rem if a;echo==a;echo echo a;echo
  21. -> if a == a echo echo a;echo
  22. echo a;echo
  23. -> echo if a;echo==a;echo echo a;echo
  24. if a;echo==a;echo echo a;echo
  25. 请按任意键继续. . .
复制代码
把分号换成逗号、等号效果一样。

可见预处理时对for、if的“参数”有特殊对待,会先把非空格分隔符统一处替换成空格。而for、if引导的命令中的分号、逗号、等号等不改变。
作者: applba    时间: 2011-5-26 19:39

本帖最后由 applba 于 2011-5-26 19:40 编辑

19# zqz0012005


虽然我没认真学过C,但是还是看懂了,这个对原理解释的比较透,但是有官方根据吗?还是自己想象出来的呢?或者是逆向的?
作者: applba    时间: 2011-5-26 19:45

本帖最后由 applba 于 2011-5-26 20:38 编辑

运行前,cmd.exe对命令字符串进行一些处理,主要是特殊符号的解释。
还包括分辨出哪些是命令名,哪些是参数,具体依据是各种特殊符号(空格、逗号等分隔符)。

cmd.exe对一个“命令字符串”进行识别时,第一个空格之前的内容被识别为“命令名”。
例证:for^ /l %%i (1,1,5) echo %%i ,这里转义了第一个空格,结果运行提示
'for' 不是内部或外部命令,也不是可运行的程序或批处理文件。
第一个空格之后的剩余字符串,如果有可用的分隔符,会继续进行进行参数的分割。
如果使用了双引号或者^等转义了这些分隔符,第一个空格之后的所有剩余字符串会被当作一个整体参数传递。

for运行时,会再次识别这些转义后的特殊符号(空格,逗号等参数分隔符),并自行对他们进行解释(如参数分割)。
当然了如果上面一部的预处理已经分离出了全部或者部分的参数,下面不会重复进行分离。

for的自行解释过程是按照顺序进行的,首先看第一个空格后有没有 /开关,比如是for /f。
例子 for  /f delims^=^+   %%a in ("123+456")  do echo %%a
接着看下一个空格后是不是option,这个option必须是一个连续的字符串。
如果有空格,option会被分割,这个空格后的内容会被当作下一个参数。
但是for 此时只认为下一个参数只能是%%a,所以运行是提示 “此时不应有 *”。
如果有option中有空格或者其他特殊字符导致option被分割时,需要使用引号或者^来。

我觉得各个option之间的处理是通过关键字来判断的,即空格是是切割参数的,而不是切割option的
处理到option参数时,里面的空格会被丢弃。

处理完option之后,下一个空格后的内容只能是%%i,如果不是提示非法。
下一个空格后就是双括号了,再下一个空格之后就是do关键字了,如果不是提示非法……
下一个空格后就是具体的命令、语句或者语句块了,这个没什么好说的了……

%%i经过运行前的预处理,成为了%i,%i在for运行时被解释,即替换(或扩展)成具体的值。



同样call也能再次识别转义后的特殊符号,包括% ^和空格等。
只是call和for的解释机制有出入。
作者: zqz0012005    时间: 2011-5-26 19:58

运行前的处理就是预处理。
从上面例子看for和if会影响预处理的。
再结合前一个例子,按一般理解,for /f 的 "usebackq skip eol tokens delims"等选项必须用引号引起来,可能就是为了让它整体作为一个参数传递给for“函数”(就象路径中有空格时也需要引号引起来),但可能因为预处理的特殊对待,不用引号也行,方法是对分隔符加^进行转义。但这种方法对其他程序无效,就像没转义一样,参数个数还是实际那么多。
作者: zqz0012005    时间: 2011-5-26 20:06

还有一个特殊的地方是
-> for.exe tokens^=1-3
argv[0]: `for.exe`
argv[1]: `tokens=1-3`

-> test.bat tokens^=1-3
%0: `test.bat`
%1: `tokens`
%2: `1-3`

同样的参数,程序和bat脚本竟然认为个数不同。而且不加转义符号结果一样。
看来是对合法分隔符的识别问题。
CMD会把分号、逗号、等号等都当作分隔符,但其他程序不这么认为。
作者: plp626    时间: 2011-5-26 20:07

看得心慌,19楼的代码真的看懂了么?

那个for.exe命令行输入
  1. for.exe a=b=c x;,y 5678"\"\""" ....
复制代码
然后再输入
  1. for.exe /f delims=+ tokens=1-3 %a in ("fdf""dfd\"\"")do ^^echo %a
复制代码
体会下;

另外,cmd对代码预处理后的结果就是
在cmd开启echo on 后在屏幕上显示的结果;这个界定适合脚本也适合命令行;

我们看预处理做了哪些工作,用echo on的方法就行了,再做“批处理物理实验”就绕弯路了;
作者: CrLf    时间: 2011-5-26 20:07

个人认为/f开关是for所有开关中最重要的一个,对于新手甚至部分老手要掌握这个/f开关的所有参数及其用法是有一定难度的。。。

关于eol,usebackq,skip,tokens,delims这五个/f开关下的参数,记得cn-dos的9527有一篇 ...
batman 发表于 2011-5-25 19:30

基于for的参数不需要空格分隔的理论基础,老兄这说法也大有问题,而且哪怕用上空格来分隔,似乎也不惧:
  1. @echo off
  2. for /f "delims=, tokens=1,2 eol=e skip=1" %%a in ('
  3. "echo skip&echo eol&echo 显 示,不显示"
  4. ') do echo %%a
  5. pause
复制代码
该显示的仍然显示了,不该显示的也同样没有显示,并不因为“delims=,”后跟空格而造成误判。看来for对于参数的划分有点像cmd对于重定向的划分,虽然在cmd回显中看不到,但是我想,for对参数的划分应该也是和cmd同样的从预处理到执行的步骤:
1、转换分隔符为空格,如果不存在分隔符则自动加上空格(就像cmd会把“echo>nul 不显示”预处理成“echo 不显示 1>nul”一样)
2、读取参数#@!@@#¥!……

另外,顺便提一个疑惑,如果for真的是函数,如何解释for在语块中不能对其参数使用带有延迟性质的变量呢?
作者: zqz0012005    时间: 2011-5-26 20:13

要说的是,那段c代码跟cmd的for完全没关系,只是一段再普通不过的代码,打印出所有的命令行参数。
只是为了试验对分隔符转义后,可不可以让多个参数被整体当作成一个参数。
作者: zqz0012005    时间: 2011-5-26 20:32

命令行的POSIX规范:
以一个横杠开头的为选项。
如果不带参数的话,多个选项可以写在一个横杠后面。如-abc与-a -b -c的含义相同。
选项名是单字符的英文字母或者数字。
某些选项是带参数的。
选项和它的参数既可以分开写也可以在一起,grep选项中的 -A 10 与 -A10都是合乎规范的。
选项参数写在非选项参数之前。
如果一个参数只是两个横杠--,那么它会结束所有的选项,所有跟在它后面的参数都被视作非选项,即使它们前面有一个横杠。
一个单横杠-被解释为普通的非选项参数,通常它用来表示对标准输入和输出流的输入或者输出。
选项之间可以是任意顺序,也可多次出现,由程序负责对此进行解释。

微软似乎喜欢和POSIX对着干。
Windows下满足这一规范哪怕是其中几条的命令寥寥无几,xcopy、findstr等命令的参数可以写在一起,这样看来for /f 勉强也算上吧。
作者: applba    时间: 2011-5-26 20:34

23# applba


我总结一下:
运行前的预处理,如果有可用的(即没有被转义)分隔符(如空格、逗号等)是会进行参数分割的。
如果没有可用分隔符,把第一个空格后的所有字符串作为一个整体参数传递。
这个过程是cmd .exe来完成的。

有些命令运行时会再次识别转义后的特殊字符,并再次启动解释工作。
比如call会再次识别转义后的%、^、空格等。
for也会再次识别转义后的空格等
作者: zqz0012005    时间: 2011-5-26 20:50

for、if应该的确是“关键字”而非一般命令,
预处理时就把参数传给它们了,从而它们也进行并影响预处理,而不是等cmd.exe先预处理完了再调用for。
上面提到的把非空格分隔符替换为空格,就是一个例子:
bat中 for %%a in (a;echo) do echo a;echo
预处理后是这样的:
for %a in (a echo) do echo a;echo
作者: CrLf    时间: 2011-5-26 20:59

关键字又是什么概念?如果能弥补“函数论”的缺陷,我不介意叛变...
作者: zqz0012005    时间: 2011-5-26 21:05

所有内部命令都相当于是一个函数好吧
作者: qzwqzw    时间: 2011-5-26 21:29

19楼的代码似是而非
又没有处理转义符号
不能作为for命令语法分析的参考

把cmd内部命令理解为函数未尝不可
但不要生硬套用函数模型来强解命令行分析

for和if不是关键字而是命令
官方文档提到的关键字
是for命令中的in、do、eol、skip、delims、tokens、usebackq
以及if命令中的not、exist、defined、errorlevel
诸如此类批处理命令中组成命令语法的固定字词
关键字本身不应该具有任何解析上的含义

关于预处理我倾向于这样定义
在批处理中开启echo on后语句所显示的形态即预处理的结果
这个过程cmd对所有语句是统一处理的
此后cmd对语句的语法分析会针对不同命令而有不同
比如各命令对于命令分隔符的处理牵扯到语法分析而各有差异
因此不应算作cmd预处理的范畴
作者: CrLf    时间: 2011-5-26 21:38

19楼的代码似是而非
又没有处理转义符号
不能作为for命令语法分析的参考

把cmd内部命令理解为函数未尝不可
但不要生硬套用函数模型来强解命令行分析

for和if不是关键字而是命令
官方文档提到的关键字
是f ...
qzwqzw 发表于 2011-5-26 21:29

似乎一步一步地明朗化了
作者: zqz0012005    时间: 2011-5-26 22:00

19楼代码的目的已经说了,只是为了试验对分隔符转义后,可不可以让多个参数被整体当作成一个参数。
验证结果表明,就算转义了,对其他命令来说,仍然是不同的参数,而不是整体作为一个参数。
作者: zqz0012005    时间: 2011-5-26 22:07

delims与空格的一个问题
http://www.bathome.net/viewthread.php?tid=3692&page=1#pid23376
好像是for的一个bug:一般来说,多个相同字符会被当作一个字符(它们不是整体作为分隔符,新手往往问到这个问题)。但如果指定连续多个空格,空格将无法作为分隔符。
补充以前讨论的一个要点:如果分隔符集里面含有空格,空格必须放在最后。
  1. @echo off
  2. for /f "delims=aa" %%a in ("1a2") do echo %%a
  3. rem 下面的“宽空格”是两个空格(也可以更多)
  4. for /f "delims=  " %%a in ("1 2  3") do echo %%a
  5. for /f "tokens=1,2 delims=aa  " %%a in ("1 2a3  4") do echo %%a.%%b.
  6. pause
复制代码

作者: applba    时间: 2011-5-26 22:08

36# zqz0012005


由于某些原因,在运行前的预处理时 没有能够分割参数,这些参数会被作为一个整体传递给具体命令然后由具体命令再次进行参数分割。for和call会这么做的。当然有些命令是不会这么做的,比如echo。
作者: qzwqzw    时间: 2011-5-26 22:11

19楼的GCC代码中的词法分析
与cmd中各命令的词法分析大有不同
编译出的for.exe不等同于cmd的for命令
放在这里容易混淆读者的理解
与楼上贴出这段代码的立意相违背
所以我才刻意强调不要参考它来理解for命令的行为

转义字符^只有对于cmd的预处理才有意义
之后的内外部命令分析和执行时是看不到的
也就不具有任何转义的意义
作者: qzwqzw    时间: 2011-5-26 22:27

本帖最后由 qzwqzw 于 2011-5-26 22:28 编辑

同意36的的见解
当然某些措辞需要修改一下
“由于某些原因,在运行前的预处理时 没有能够分割参数”
应该说
cmd的预处理不会进行命令行的词法分析
因为它认为这是各命令自己的事情

另外for中其实最容易出问题的倒是usebackq
不仅会产生与正常理解相异的行为
而且可能还会泄露部分内存的数据
Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.

C:\Documents and Settings\Administrator>for /f "usebackq"  %f in ('df df') do ec
ho %f

C:\Documents and Settings\Administrator>echo df
df
系统找不到文件 。

C:\Documents and Settings\Administrator>for /f "usebackq"  %f in ('df df') do ec
ho %f

C:\Documents and Settings\Administrator>echo df
df

C:\Documents and Settings\Administrator>

作者: zqz0012005    时间: 2011-5-26 22:34

被你发现了,我故意取名为for.exe,就是为了混淆一下,看看大家会不会仔细分析我帖的那些代码。
我后面也说了,这个for.exe与cmd的for完全没有关系。

通过它对参数的解析来对比,再结合for /f 常规用法是需要引号把参数括起来(可能的目的是整体当成一个参数),主要论点是如果不用引号,而是把分隔符转义,for /f 的各个函数对for来说是不是整体作为一个参数。如果这个观点成立,则进一步得出for、if也要参与预处理的观点。
再帖一下:
bat中 for %%a in (a;echo) do echo a;echo&findstr /v ; C:\boot.ini
预处理后是这样的:(不用说,打开回显即可看到)
for %a in (a echo) do echo a;echo  & findstr /v ; C:\boot.ini
注意,括号中的分号被替换成了空格,do后面命令中的则没变。
作者: qzwqzw    时间: 2011-5-26 22:47

本帖最后由 qzwqzw 于 2011-5-26 22:49 编辑

for和if命令都要重建语句块
以插入到echo on的运行时序中

因此
如果说echo on的内容都是预处理得来的
那么可以说for和if参与了cmd的预处理
并把自己的语法分析过程也带到了预处理过程中
作者: powerbat    时间: 2011-5-27 01:25

for、if应该的确是“关键字”而非一般命令,
预处理时就把参数传给它们了,从而它们也进行并影响预处理,而不是等cmd.exe先预处理完了再调用for。
zqz0012005 发表于 2011-5-26 20:50

同意这个观点。

结合21楼的例子和结论:可见预处理时对for、if的“参数”有特殊对待,会先把非空格分隔符统一处替换成空格。而for、if引导的命令中的分号、逗号、等号等不改变。
如果不是有特殊对待(或者说for、if没有参与预处理),那为什么要把for、if参数部分中的非空格分隔符统一替换成空格?

23楼
例证:for^ /l %%i (1,1,5) echo %%i ,这里转义了第一个空格,结果运行提示
'for' 不是内部或外部命令,也不是可运行的程序或批处理文件。

把for换成其他命令,就不会报错。所以这个反而例证了for的特殊性。if类似。

7楼
我一直认为空格本身就不能通过^转义的;
为什么在for中就是例外?

可能真的就是例外。
对普通命令来说,就算预处理时空格确实被转义了,但普通命令是cmd在预处理才调用它并把参数传给它,传递的还是实际空格,转义已经不存在了。
而对for不一样,参数是预处理就传给它了,这时转义符是存在的,for也参与预处理,告诉cmd甚至是它自己决定怎么对待特殊字符。
比如那个for.exe,一个普通外部命令,cmd就是在预处理后才调用它并传参数,由于参数是空格隔开的,所以for.exe看到的参数是多个。
而for /f tokens^=1^,2^ delims^=^" %%a in ("a"b"c") do echo %%b,由于有转义符,for看到的option部分是只是一个参数[tokens=1,2 delims="]
作者: powerbat    时间: 2011-5-27 01:34

本帖最后由 powerbat 于 2011-5-27 01:42 编辑

29# zqz0012005

原来命令行还有个POSIX规范?

=============
google了一下,POSIX是Portable Operating System Interface of Unix的缩写,这个标准主要是Unix/Linux下遵循的。
不过也看到维基百科“微软的Windows NT至少部分实现了POSIX兼容”。
cmd下各个命令及系统自带的外部命令 参数风格确实不太统一。如果也遵循POSIX标准,会方便很多。
作者: powerbat    时间: 2011-5-27 09:17

另一个有力的证据是,for /f 的选项中不支持!!引用的的延迟变量。(以下代码前提当然都开启了)
set n=1&for /f "tokens=!n!" %%a in (循环集) do ... //出错
很可能就是因为for /f 是在预处理时解析参数的,这时由于不展开延迟变量,传递给for的就是!n!形式的字符串,而for内部处理这些选项时,发现传给tokens的值是非数字,所以马上报错。

set "str=1a2@d@e@l@i@m@s^^^!3^!4"
for /f "delims=" %%a in ("!str!") do echo %%a
set delims=a
for /f "tokens=1-8 delims=!delims!" %%a in ("!str!") do echo %%a.%%b.%%c.%%d.%%e.%%f.%%g.%%h

结果如下:
C:\>for /F "delims=" %a in ("!str!") do echo %a

C:\>echo 1a2@d@e@l@i@m@s^!3!4
1a2@d@e@l@i@m@s!34 //不要问第2个感叹号为什么消失了,你懂的。

C:\>set delims=a

C:\>for /F "tokens=1-8 delims=!delims!" %a in ("!str!") do echo %a.%b.%c.%d.%e.%f.%g.%h

C:\>echo 1a2@.@.@.@.@.@.^.3
1a2@.@.@.@.@.@.^.3

可见,for不是以变量的!delims!值作为分隔符,而是这个字符串本身(包括感叹号)。
所以for的确是在预处理时就得到了参数字符串,for内部就记住了将要用什么去分割。后来不管这个分隔字符串是否要进行变量展开,已经影响不到for内部记住的东西了。


这像这个例子:
http://www.bathome.net/viewthread.php?tid=12324&page=3&fromuid=29086#pid79319
猜想CMD把for /L 语句转换为C语言是类似这样的:
for /l %a in (start,step,end) do ...
==>
int i = 0;
int iStart = getenv("start");//假设for /L 的三个值都是变量
int iStep = getenv("step");
int iStop = getenv("end"); //在执行C语言的for之前已经把条件都确定了
for (i = iStart; i < iStop; i += iStep) {...} //在循环体中再怎么改变start,step,end,已经不影响for的条件了

作者: plp626    时间: 2011-5-27 15:15

45# powerbat


【选项部分的参数】如何改变一直没方法(对大多数人,但我不敢断言就一直没方法);

【括号里的参数】在循环体内改变,这样的例子 【不胜枚举】;
  1. for %%a in (1 2)do set loop=%%a&for /l %%b in (1 1 !loop!)do echo %%b
  2. Set loop=1 1 2
  3. for %%a in (1 1) do for /L %%b in (!loop!) do Set loop=626 1 627& ECHO %%b
复制代码
你这个C语言代码推测很容易被推翻。
作者: CrLf    时间: 2011-5-27 15:54

我原以为,for是以类似%1的形式接受参数的,但是下面这个怪异现象又让我迷茫了:
  1. for /f "delims= "tokens^=2 %%a in ("haha test") do echo %%a
  2. ::正确
  3. for /f tokens^=2"delims= " %%a in ("haha test") do echo %%a
  4. ::出错
复制代码
第一条可以执行,的二条却出错,这就与call的情况不一样了,为什么呢?
作者: powerbat    时间: 2011-5-27 18:29

46# plp626

你没理解我的意思:
for /l %a in (start,step,end) do ... //在循环体中再怎么改变start,step,end,已经不影响for的条件了
这里指的是类似这种方式:
set /a start=1, step=1, end=3
for /l %%a in (!start!,!step!,!end!) do ping -n 1 192.168.0.%%a >nul && set /a end+=1
这样是无法改变循环条件的。

既然括号里面的参数可以是变量,当然可以在for之前改变变量值,然后再运行for,也就是你那种情况,但与我说的完全不是同一种类型。
作者: caruko    时间: 2011-5-27 18:36

for 是内部命令,无需那种调用外部程序时带的参数。

如果for是外部命令,那么for %%i do (set x=%%i) 就无法实现,因为FOR如果不是内部命令,就无法更改FOR外部的全局变量。

同时,大多数外部命令,没有打开stdin的,都不接受 ( 多行语句文本 ) 。

而打开stdin的比如findstr,也是在findstr运行之后才打开stdin,无法在传递参数的初始阶段就接受括号 () 包裹的多行文本。
作者: powerbat    时间: 2011-5-27 19:22

47# zm900612


for /f "delims= ""tokens=1-3" %a in ("aa bb cc") do echo %a.%b.%c
这样不会报错,但结果是aa.%b.%c,好像tokens=2未起作用。

for /f "eol=a""delims= ""tokens=1-3" %a in ("aa bb cc") do echo %a.%b.%c
这样也没问题,而且eol生效了。

for /f "eol=b""delims= ""tokens=1-3" %a in ("aa bb cc") do echo %a.%b.%c
结果:aa.%b.%c,虽然eol生效了,但后面的不生效。

for /f eol^=a"delims= ""tokens=1-3" %a in ("aa bb cc") do echo %a.%b.%c
出错:此时不应有 "delims= ""tokens=1-3"。

for /f "delims= ""tokens=1-3""eol=a" %a in ("aa bb cc") do echo %a.%b.%c
这样没问题,但eol不生效。

for /f "delims= "tokens^=1-3eol^=a %a in ("aa bb cc") do echo %a.%b.%c
很好,不出错,而且所有选项均生效了。

for /f "usebackq delims= "tokens^=1-3eol^=a %a in ("aa bb cc") do echo %a.%b.%c
“系统找不到文件 aa bb cc。”,但这不是语法错误,而是for已经成功运行了,只不过找不到文件(找不到才正确,本来就没有)

for /f "usebackq""delims= "tokens^=1-3eol^=a %a in ("aa bb cc") do echo %a.%b.%c
也不出错,但除了usebackq外其他选项不生效。

for /f "usebackq"delims^=^ tokens^=1-3eol^=a %a in ("aa bb cc") do echo %a.%b.%c
这个当然没问题啦,都生效。

回到开始:
for /f eol^=a"delims= " %a in ("aa bb cc") do echo %a.%b.%c
出错:此时不应有 "delims= "。

看来跟引号的位置有关系,大致如下:
如果引号出现在所有选项前,则第一对引号中的选项都有效;后面如果还有引号包含选项则其中的选项不生效;如果只有一对引号,引号外面还有选项,则可以生效。
如果在引号出现前已经有选项,则如果把后面的选项用引号包含起来会出语法错误。
作者: powerbat    时间: 2011-5-27 19:26

上面的结论好像也不完全对。
for /f "usebackq"delims^=^ tokens^=1-3eol^=a %a in (`echo aa bb cc`) do echo %a.%b.%c
结果:aa.%b.%c
后面的选项没生效。

for /f "usebackqdelims= "tokens^=1-3eol^=b %a in (`echo aa bb cc`) do echo %a.
%b.%c
aa.bb.cc
这个却OK,都生效了。

难道usebackq有点特殊?
作者: plp626    时间: 2011-5-27 19:33

45# powerbat


括号里的参数是for的入口的参数,它改变后,重新调用这个for接口就可被再次读取;
这也就可以说明为什么
  1. set x=0
  2. for %%a in (1 2 !x! !x!)do echo %%a&set x=y
复制代码
不能改变;而
  1. set x=0
  2. for %%z in (1 1)do for %%a in (1 2 !x! !x!)do echo %%a&set x=y
复制代码
却被改变的原因;
=============================================
对于选项部分的参数(不知道该怎么叫,大家理解就好)我也仅是靠现象猜测(仅是便于理解):

选项部分的参数直接和for接口函数功能相关联,但在预处理的时候就被读取固定下来;
只要是在这个预处理阶段读取的语句,不管这个语句怎么改变选项部分的参数
能改变的仅仅是参数的值,而非这个for接口的函数功能了;

作者: powerbat    时间: 2011-5-27 19:35

49楼又给了我提示。
为什么只有for、if这两个命令可以引导括号包含的多行语句块?(当然干脆不要任何命令引导,单独使用括号也是语句块)
说明预处理时看到有for、if,对待就不同了,所以for、if肯定是参与了预处理的。
由此看来for、if的确有关键字的特征。
作者: CrLf    时间: 2011-5-27 20:15

47# zm900612


for /f "delims= ""tokens=1-3" %a in ("aa bb cc") do echo %a.%b.%c
这样不会报错,但结果是aa.%b.%c,好像tokens=2未起作用。

for /f "eol=a""delims= ""tokens=1-3" %a in ("aa bb cc") ...
powerbat 发表于 2011-5-27 19:22

我晕了,昨天只是想到call参数的特性,试了一下,没研究这么多。
佩服
作者: powerbat    时间: 2011-5-27 20:42

52# plp626


for %%z in (1 1)do for %%a in (1 2 !x! !x!)do echo %%a&set x=y
外层的for要展开语句的,里面的语句执行一次后,变量值改变了,这是在第二次for运行之前,当然有效了。
它和把for写成两行没什么本质区别:
for %%a in (1 2 !x! !x!)do echo %%a&set x=y
for %%a in (1 2 !x! !x!)do echo %%a&set x=y
作者: plp626    时间: 2011-5-27 20:45

55# powerbat


是这样:
  1. (
  2. for %%a in (1 2 !x! !x!)do echo %%a&set x=y
  3. for %%a in (1 2 !x! !x!)do echo %%a&set x=y
  4. )
复制代码

作者: cjiabing    时间: 2011-5-28 02:38

本帖最后由 cjiabing 于 2011-5-28 02:40 编辑

token与delims的困惑:
在以下处理中,在“tokens=* delims=o”一行命令中,已经定义了小写字母“o”为分隔符,为何后面显示出来的时候,还是显示字母“o”?
即使使用“tokens=1,2,* delims=o”,最后几个字母“o”仍然会出现。
在我们的理解中,被定义为分隔符的字符默认是被忽略不显示的,但以上“会显示的分隔符”让人困惑。
类似的问题很多,在定义分隔符提取指定列时,对此往往很无奈。delims或者tokens会消极怠工,不按规定完成任务。
  1. @echo off
  2. for /f "skip=25 usebackq tokens=* delims=echo" %%a in (%0) do echo %%a
  3. echo,
  4. echo, 注意观察最后一行的字母“o”。
  5. echo,
  6. pause
  7. cls
  8. for /f "skip=25 usebackq tokens=* delims=o" %%a in (%0) do echo %%a
  9. echo,
  10. echo, 注意观察最后一行的字母“o”。
  11. echo,
  12. pause
  13. cls
  14. for /f "skip=25 usebackq delims=o" %%a in (%0) do echo %%a
  15. echo,
  16. echo, 注意观察最后一行的字母“o”。
  17. echo,
  18. pause
  19. cls
  20. for /f "skip=25 usebackq tokens=1,2,* delims=o" %%a in (%0) do echo [%%a] [%%b] [%%c]
  21. echo,
  22. echo, 注意观察最后一行的字母“o”。
  23. echo,
  24. pause
  25. exit
  26. echo.&echo.
  27. echo. &set/p=按任意键返回&cls&
  28. echo.使用说明:
  29. c
  30. ch
  31. sssssssss echo eeeeeeeee
  32. ececechechoechoochochco
  33. eceho&echo&echoddls
  34. i love you,i love bathome.
复制代码

作者: caruko    时间: 2011-5-28 10:01

57# cjiabing


tokens=m-n* 的情况下,n之后的字符串不会被分割,这在 for /?中有明确说明。

如果还要分割,那么会破坏字符串,无法得到预期的要求,特别是长字符串的时候,出现预料外的分割的话,无法还原这个字符串了。
作者: cjiabing    时间: 2011-5-28 13:46

58# caruko
老兄,可为什么我用“tokens=*”的情况下它仍然不显示呢?
作者: batman    时间: 2011-5-30 08:47

57# cjiabing
兄弟有点丢基础了。。。
作者: cjiabing    时间: 2011-10-7 23:51

本帖最后由 cjiabing 于 2011-10-8 00:02 编辑

回复 60# batman


    哈哈,当时犯糊涂了,现在看都好笑。
    另外,谈谈对FOR /F 选项的一些经历:
    记得前阵子看过类似这个
  1. for /f tokens^=1*^ delims^=^" %%a in ("sd"z"vc") do echo %%b
复制代码

    当时我也犯糊涂了,怎么FOR的tokens的=号前还要转义符呢?但我很快想到,在cmd中,特别是cmd的嵌套中,注意,这个cmd是指在批处理文件里的命令 cmd /q 里的FOR的等号也是需要转义的。如:
  1. for /f "tokens=1*" %%i in ('cmd /v:on /c "@echo off&for /f "usebackq tokens^=*" %%a in ("%1") do (echo ^!random^! %%a)"^|sort') do echo %%j
复制代码

    在这里,第二个FOR必须用转义符,一般在FOR内部保留处理默认分隔符时,一般都需要特殊处理,如:
  1. C:\>for %a in (=) do echo %a
  2. C:\>
  3. C:\>for /f %a in ("=") do echo %a
  4. C:\>echo =
  5. =
复制代码

    如果把外面的FOR去掉,以及把所有转义符去掉,这样也可以:
  1. cmd /v:on /c "@echo off&for /f "usebackq tokens=*" %%a in ("%1") do (echo !random! %%a)"|sort
复制代码

   
  1. cmd /v:on /c "@echo off&for /f "usebackq tokens^=*" %%a in ("%1") do (echo ^!random^! %%a)"|sort
复制代码

    如果不去掉FOR里面的转义符也可以,但“|sort”这个前面的转义符要去掉。那么这里就有一个问题了,为什么这里用不用转义符都一样?难道转义符失灵了?
    通过以上大家可以对FOR命令里的符号有了更多的认识。
    plp626的代码,
  1. for /f tokens^=1*^ delims^=^" %%a in ("sd"z"vc") do echo %%b
复制代码

    在命令提示符窗口也可以执行,但如果去掉tokens=后(转义空格)与delims=(转义双引号)前的等号的转义符,命令就会提示“此时不应有 1* delims。”
    可见,在这里,必须用转义符,否则命令失效。但你想起一个问题没有,FOR命令语法的参数是要用双引号引住的!
   
  1. FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
复制代码

    看看,这里["options"] 是要用引号的。而楼主的代码没有使用引号。delims后面的一个双引号被转义成分隔符来使用了。因为在命令中,引号一般都是成对出现的,少一个往往会引起错误,而这里没有,证明被转义了。如果你在tokens^=1*^ delims^=^"外面添加一对双引号,命令就会出现语法错误。而如果你把转义符全部去掉,直接“delims="”,这样是会出错的,因为双引号不能作为转义符。
    就像powerbat 所做的测试,在FOR /F后面的选项中,使用双引号与否、使用的位置、数量等都会影响到命令的执行,我也曾经做过这类的试验。比如这样的“for  /f  "tokens=2" "delims=。" %%a in……结果只有一个运行得了。
    从这些问题上看,这些参数的变化正反应出FOR的运行规律。
作者: cjiabing    时间: 2011-10-8 01:29

再谈谈FOR的静态部分和动态部分。
  1. FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
复制代码

在FOR中,有几个地方是FOR的基本语法,不能改变:
1、FOR /F  静态部分
开头表明FOR命令,/F参数,用以区分其他命令和其他参数。
2、["options"]  动态部分
选项可选,并且部分要求高,要求顺序等,而部分要求不高,可以省略空格。我想,在FOR读到此处时,此处类似于一个FOR命令:
  1. for /f "tokens=1,2* delims=, " %%a in ("tokens=1,2,3 delims=, ") do echo %%a %%b
复制代码

提取选项关键词和数值,然后进行核对和处理。
选项外的双引号只是一种便于识别的辅助符号:
  1. C:\>for /f "tokens=1" %i in ("4 2 3")do @echo %i
  2. 4
  3. C:\>for /f tokens^=1 %i in ("4 2 3")do @echo %i
  4. 4
复制代码

而使用转义符才是根本,可能在使用多个转义符时,顾及麻烦,便舍弃转义符而偏爱双引号。而且,在编程过程中,使用双引号引住全部选项也符号常理。
为什么要进行转义呢,可能涉及到一些分隔符之类的特殊符号的处理。
3、变量%variable 动态部分
变量也是一个可以改变的部分。%%a批处理,%a命令提示符。批处理是一种脚本,%%a最终需要转化%a给cmd.exe处理。
一般输入变量能改变的较少,主要是输入变量前后要使用分隔符,不能与参数和IN连在一起。
4、in  静态部分
5、(file-set)   动态部分
集合可以是命令、路径和字符串。
6、DO  静态部分
7、command [command-parameters]   动态部分

整个下来:
FOR /F 动态选项  动态变量%%a in  (动态集合) do  动态命令
FOR——(附加参数)——IN——(指明集合对象)——do——(指明动作)
静态部分是指不能改变的FOR的结构,它们之间必须使用分隔符(而不仅仅是空格,还包括其他默认的分隔符),否则出错。
动态部分是指可以选择的各个参数、变量、对象、动作等,可以自由改变,它们之间有些不必用分隔符。
  1. for /f  ,%%a, ,,in("你好") do echo %%a
复制代码

看来默认分隔符在FOR当中是一个比较普遍适用的。
来猜测一下FOR的大概过程:
在命令窗口时代,输入%%a是要比输入%a要吃力的,而到了脚本时代,难道编程的大哥不怕麻烦了吗?估计从脚本转入cmd.exe执行时,有一个丢失百分号的问题(脱层)。为何会丢失呢?是否是与DOS执行区别?如果无法执行也不必做区别的,原因需要资料方可了解。
获得代码后,批处理开始获取执行顺序,预处理一定行数的代码,我们暂且定位十行吧,为什么不是全部一个bat都预处理呢?因为当它遇到一个几十M的批处理时(不要怀疑这个大的BAT,做程序要有这个考虑)如果全部预处理完的话,估计要花费相当多的时间。而实际上,我们打开一个比较大的批处理,一般不会出现卡住的情况。也或许它获得一行处理一行,预处理只是对一行内的命令进行处理而已。这个不好解释。
然后到获得具体的命令,比如FOR的,以“FOR”这个词语开头的一行代码。获得这行代码后分析它是独立的一行,还是有&连接的多个命令。但是,按照我的实践理解,FOR命令在遇到“FOR”并一路按照FOR的语法来判断这个FOR是否合法,从FOR到/F到选项到输入变量……,只要中间出现一个问题,批处理马上退出。实际上也是这样,所以,批处理的预处理只是针对类似FOR一类的命令,针对执行到的某一行,而非全部命令。因此,如果批处理真的是只按照FOR命令的语法从左到右进行判断,一旦遇到问题马上停止,那么,在没有判断一条完整的代码的情况下,也就是当FOR命令只执行到IN的位置,因为IN和括号连到一起了,发生错误,这时,批处理怎么知道命令是否正确呢?或者,命令是怎么区分出FOR、/F、tokens=、delims=等等命令、参数、选项、变量、符号等?这时,基本的语法结构就发挥很大的作用了,除此之外,利用分隔符可以很好的处理这些元素之间的距离和关系。分隔符的作用就是用来区分元素之间的,如果没有分隔符,容易致使两个命令或参数混淆。但我们也发现,tokens=1delims=m,这里的两个选项搅合到一起了,FOR还是能够认出他们。这么说,获得关键词这时就发挥作用了。比如“tokens=1-3delims=:”这个是正确的,但是“tokens=d1-3delims=:”“tokens=1-3ddelims=:”“tokens=1=3delims=:”“tokens=1-3,8delims=:”等都是错的。这就证明了,FOR是直接提取这两个选项的。
在处理完参数、输入变量之后,就到集合了,集合的处理存在预处理,它有可能是字符串,也可能是路径、命令之类的,特别是命令,需要预先处理,那么,这里就存在一个暂停,FOR暂停,等待集合中的命令先执行。而在这些命令执行前,FOR会先检查代码的是否符合语法。
至于到了DO后面的组合,这个也和集合差不多,存在一个暂停、预处理的过程。
因此,FOR的执行,首先检查是否合乎语法,第二预处理是否能够成功执行,第三才是真正的回显执行过程。
FOR和CALL、goto loop等差不多,只是他将一个重复的动作放到了FOR之中,使得代码更加简便,效率更高。
作者: powerbat    时间: 2011-10-8 19:00

Linux Shell 的秘密早就被摸透了(或者说本来就没有秘密),Windows CMD 至今还是一片混沌。不能怪Windows不开源,只能再次证明玩Linux的大多数确实都是高手(至少会C语言)。Windows下的高手其实也不少,但可能都不屑于玩cmd(这些东西对他们来说可能真的太简单)。
作者: 狗屁不通    时间: 2012-8-26 21:48

好帖啊,不能沉了
作者: amwfjhh    时间: 2014-11-12 17:40

拜读完各楼高论,感觉好酣畅淋漓……
不知道从哪里看到一句:"号与^号都是转义符号,从这个角度来理解这些行为,或许要容易接受些,至于几个""与^连用及其先后顺序导致的不同结果,可不可以理解为^的转义优先级高于"的转义优先级,因此"转义的内容可以接着连接^转义的部份,而^转义的部分则默认所有的内容都必须是^转义的,导致其后的"转义不合法?
作者: 慕夜蓝化    时间: 2014-12-26 18:59

确实没想到for还可以这样写,但是感觉只要了解到就行了,常态下的写法会让代码看上去更舒适。
作者: LJY4.0    时间: 2022-6-12 13:21

感觉for很难




欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2