[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
本帖最后由 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的运行规律。
寂寞是黑白的,但黑白不是寂寞,是永恒。BAT 需要的不是可能,而是智慧。

TOP

再谈谈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之中,使得代码更加简便,效率更高。
寂寞是黑白的,但黑白不是寂寞,是永恒。BAT 需要的不是可能,而是智慧。

TOP

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

TOP

好帖啊,不能沉了

TOP

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

TOP

确实没想到for还可以这样写,但是感觉只要了解到就行了,常态下的写法会让代码看上去更舒适。
踏实一些点.不要着急.你想要的时间都会给你.2

TOP

感觉for很难

TOP

返回列表