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

[讨论]批处理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 %老 %耂 %考 %耄 %者 %耆 %耇 %耈 %耉 %耊 %耋 %而 %耍 %耎 %耏 %耐 %耑 %耒 %耓 %耔 %耕 %耖 %耗 %耘 %耙 %耚 %耛 %耜 %耝 %耞 %耟 %耠 %耡 %耢 %耣
复制代码
2

评分人数

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

TOP

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

call中^为什么不行,为什么call会对字符的^加倍扩展一次。

TOP

本帖最后由 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参数最好(先前错误地写为必须)一个在最前一个在最后,至于为什么,大家可以思考一下了。。。
***共同提高***

TOP

以引号作为分隔符确实是批处理研究中的一大突破
进而引发了对参数分隔机制的探讨
能解决很多实用的问题
那个帖子应该加精
至少是高亮
这样才能引起更多人的注意
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

本帖最后由 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^=^"
2

评分人数

TOP

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

TOP

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

TOP

原来把 options 的=" 转义,就可以省略"",从而做到使用"做分隔符,又学到一招。

TOP

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

TOP

个人不建议省去for/f各个参数间的空格,代码除了简洁还要讲究可读啊。。。
***共同提高***

TOP

本帖最后由 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
复制代码
上面的例子中转义了逗号和管道符号。

TOP

6,11楼的话可以结合来看,for /f 各个参数之间的空格可以省略,但为了程序的可读性最好别省略。

TOP

本帖最后由 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 命令

TOP

本帖最后由 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
复制代码

TOP

返回列表