Board logo

标题: [原创] 对“批处理for语句从入门到精通”的找茬行动 [打印本页]

作者: Hello123World    时间: 2011-9-16 20:37     标题: 对“批处理for语句从入门到精通”的找茬行动

我记得第一次看到这篇“批处理for语句从入门到精通”的时候,有一种“拨云雾而见天日”的感觉,以前也不是没有学过for,但是总不得要领。

在这里真诚感谢namejm大大花心力写了这么篇好贴。

随着不断在bathome学习、讨论、回答问题,能力也是与日俱增,再回首看这篇“批处理for语句从入门到精通”,除了感叹于namejm在写作上功力不俗外,也发现了不少错漏之处(这点是在所难免的,for命令是批处理的灵魂所在、内容之丰富到了“令人发指”的程度,想要以一人之力写一篇深入浅出、面面俱到的入门教程无疑是一件近似于不可能完成的任务)。

近日学了一句话“只要眼球足够多,虫子再多也不怕”,这是开源界的一句俏皮话,通俗一点来说就是“只要找茬的人多了,错误也就少了”,这话用在这篇教程中也是适用的,所以鉴于这点,写了以上这些文字。

本想发在版主区的,但是写着写着便想到,与其借助bz的力量,不如借助众批友的力量,群众的力量是强大的,人民的力量是毁灭性的。

批处理for语句从入门到精通:http://bbs.bathome.net/thread-2189-1-1.html


找茬回帖规范:
1.账号
2.错误之处/遗漏之处
3.改正/补漏
4.详述“改正/补漏”的理由。

例如:
1.hello123world
2.错误之处:3楼,以上代码不能列出含有隐藏或系统属性的文件;
3.改正:以上代码不能列出含有隐藏属性的文件
4.理由:
  1. @echo off
  2. attrib +s 1.txt
  3. For  %%i in (*.txt) do Echo %%i
  4. pause
复制代码
这里的1.txt在结果中显示出来了。
作者: pienashuicha    时间: 2011-9-17 09:52

在找茬过程中修正错误   成长  探索 寻找乐趣
作者: qzwqzw    时间: 2012-3-3 08:32

本帖最后由 qzwqzw 于 2012-3-3 09:31 编辑

不久前在查询关于usebackq的bug信息
结果就搜索了这篇帖子
记起某个茬通过评分提交原作者至今尚无反馈
索性就准备写在这里
请其它版主代为修正

当回过头来再细看那篇经典教程时
不免又发现了一些瑕疵
说是错误也未必尽然
只是确有推敲之处
既成经典就当尽求完美
鼓励怀疑提倡讨论
不可因作者的身份就谨言慎行
否则就迷失了我们讨论的本来目的

不知道为什么版主要求的规范里还要求写帐号
帖子旁边的作者不算吗?
不过还是怎么要求怎么来吧
以下按行文顺序列出我所找到的BUG

1.qzwqzw
2.错误之处:3楼,for %I in (command1) do command2
3.改正:FOR %variable IN (set) DO command [command-parameters],其它段落中相关联的词句和术语建议同时修改
4.理由:
CMD的帮助有时还是靠得住的
况且命令文档的书写自然形成了一定的体例
像楼主的写法
说范式不像范式,因为有%%I
说例句又不像例句,因为有command1/command2
而且无法理解作者为何要将for的set换成command1
作者: qzwqzw    时间: 2012-3-3 08:38

1.qzwqzw
2.错误之处:4楼,所有的对象,无论是文件、窗体、还是控件,在所有的非机器语言看来,无外乎都是形如"c:\test.txt"、"CWnd"之类的文本信息...
3.改正:建议整段删除
4.理由:很多对象并非是单纯的文本信息,甚至大部分对象都不是纯文本信息,而是二进制数据,所以作者举的例子并不是很好
作者: qzwqzw    时间: 2012-3-3 08:49

1.qzwqzw
2.错误之处:4楼,这段代码,主要是让你树立这样一种观念:读取文本文件的内容,请使用 for /f 语句!
3.改正:将“读取文本文件的内容”改为“逐行分析文本文件的内容”
4.理由:读取文本文件内容的方法命令有很多,比如重定向输入,又比如type/more/find/sort等命令
作者: qzwqzw    时间: 2012-3-3 08:59

1.qzwqzw
2.错误之处:4楼,在这里,我们引入了一个新的开关:"delims=,"
3.改正:将“开关”改为“选项”,其它相关联内容建议同时修改
4.理由:同3楼帖,windows习惯上将命令之后以/或者-起始的命令行参数叫做开关(switch),而对于for /f 之后的控制信息,系统文档使用的是“选项/选项组”("options")
作者: qzwqzw    时间: 2012-3-3 09:24

这也算是本人所发现的第一个BUG

1.qzwqzw
2.错误之处:4楼,使用 for /f "eol=" 语句,也就是说,强制指定字符为空,就像对付delims=一样。
3.改正:建议整段删除
4.理由:以前有过讨论,"eol="会指定双引号为行注释字符,所以目前我的取消行注释字符的近似方法,使用eol指定另外一个文本中很难出现的字符作为行注释字符,比如ANSI字符集中控制区字符或者Unicode字符集中的偏僻字符
  1. for /f "eol=" %f in ("""not echo") do @echo %f
复制代码

作者: CrLf    时间: 2012-3-3 21:04

四楼,[code16] 下方第七行处
原来,for /f 语句是默认忽略以分号打头的行内容的,正如它默认以空格键或跳格键作为字符串的切分字符一样。(hello123world注:eol=;这种默认设置,在delims=;时变得无效。)

建议改成:
原来,for /f 语句是默认忽略第一节以分号打头的行(即使未在 tokens 中对第一节进行声明),正如它默认以空格键或跳格键作为字符串的切分字符一样。

作者: powerbat    时间: 2012-3-3 21:17

hello123world注:eol=;这种默认设置,在delims=;时变得无效。

这里有解释:
for /f 机制的进一步发现
http://www.bathome.net/viewthread.php?tid=5603
作者: powerbat    时间: 2012-3-3 21:24

for教程集中整理帖不要忘了这些:
http://www.bathome.net/viewthrea ... amp;page=1#pid30833
http://www.bathome.net/thread-6357-1-1.html
特别注意其中zqz版主的补充。
作者: namejm    时间: 2012-3-3 22:39

Re qzwqzw 3 楼:
记起某个茬通过评分提交原作者至今尚无反馈

  最近一年多的时间里,因为工作繁忙,另外还在准备考试,基本上很少登录论坛。某日登录论坛的时候,确实发现过qzwqzw兄在帖子中的评价消息发到站内信箱。似乎正碰上论坛程序升级,可能batcher出于节约论坛空间的考虑,以前的站内短信正文全被清空,仅能看到短信通知的纪录;而兄在帖子里的评价留言比较长,仅能显示一部分内容,关键的部分超过显示长度限制而无法阅读。当时没有太多精力来关注这个帖子,因此也就不了了之了。非常抱歉。

当回过头来再细看那篇经典教程时
不免又发现了一些瑕疵
说是错误也未必尽然
只是确有推敲之处
既成经典就当尽求完美
鼓励怀疑提倡讨论
不可因作者的身份就谨言慎行
否则就迷失了我们讨论的本来目的

  说实话,本人不仅不是科班出身,并且所从事的行业和IT领域隔了十万八千里,所以,在IT理论方面其实只是三脚猫的水平,所有的教程,只是在反复的摸索中所积累的一些心得,属于经验之谈,错误的地方肯定会很多,说那篇教程是“经典”,实在是太抬举我了,愧不敢当。从qzwqzw兄历年的帖子可以看出,qzwqzw兄功力深厚,只可惜平时很少露面,留下的帖子非常少,万望兄能多发一些帖子,把我那篇多少有点误人子弟的帖子中的错误一一指出,不甚感激。

To All:
  我之所以挂着荣誉头衔,只是因为曾经管理过论坛,并非表明我的批处理水平就一定比各位高,我所发的教程,无论是否被高亮被置顶,都不代表里面没有一点错误,各位无需把它们视为至理名言而不敢置疑,各位应当“大胆怀疑小心求证”,对有疑问的地方大胆地提出来,以求共同进步。

  最近一段时间诸事繁忙,暂时只收集各位提出的错误之处,等到稍微有空的时候再整体更正,不一定能一一回复,还请各位见谅。同时,在那篇帖子的顶楼链接本帖地址,以提醒后来的阅读者注意本帖中提出的问题。
作者: Batcher    时间: 2012-3-3 22:43

回复 11# namejm


难道是传说中的专业挖坑8级证书考试?
作者: namejm    时间: 2012-3-3 22:55

不是证书考试,挂掉了,鸟语还得从头抓起啊,唉,不提也罢,还是回归正题吧,免得一个好好的技术帖又成水帖了。
作者: applba    时间: 2012-3-4 12:16

我也想发一个for教程
作者: qzwqzw    时间: 2012-3-7 14:59

本帖最后由 qzwqzw 于 2012-3-7 17:10 编辑

1.qzwqzw
2.错误之处:5楼,首先,把一条完整的语句读入内存中(不管这条语句有多少行,它们都会被一起读入),然后,识别出哪些部分是命令关键字,哪些是开关、哪些是参数,哪些是变量引用……如果代码语法有误,则给出错误提示或退出批处理环境;如果顺利通过,接下来,就把该条语句中所有被引用的变量及变量两边的百分号对,用这条语句被读入内存之就已经赋予该变量的具体值来替换
3.改正:将“然后,识别出....顺利通过"删除
4.理由:
  1. set "cs=&"
  2. set/p=test1<nul%cs%echo test2
  3. set sw=/l
  4. for %sw% %%i in (1,1,3) do echo %%i--
  5. set cmd=errorcmd
  6. %cmd%
  7. set errsw=/k
  8. dir %errsw%
复制代码
这个问题前几天就发现了
但是为了寻求理论上的确认花费了一些时间
经过数次跟踪分析
发现CMD的词法分析机制异常复杂
为此找了一些NT4下的cmd资料
NT4的CMD不支持变量延迟扩展和很多扩展特性
分析起来相对简单
但仍然没有得到确切的结论

大致可以得出的结论是
CMD首先分析了语句符号(包括() 和 @)
以及命令连接符号(顺序大致是& || && |)
再次分析for / if / rem / 其它命令 / 下级语句
在这些分析的过程中
如果遇到变量符号%则随时进行分析扩展

所以说cmd变量扩展和词法切分是混合进行的
很多特殊符号() | & 等会导致词法切分的退字符动作
%等符号会将缓冲区的字符指针重新定位
也就是说它们都会将命令缓冲区的Token串进行重整
以便在下一步的词法分析中可以继续对扩展结果进行切分和解析
作者: cjiabing    时间: 2012-3-7 22:12

hello123world敢提qzwqzw敢说,倡导自由的讨论环境。找茬就不大好了,找不足还好,希望对作者有改进,对读者负责。大家继续!~
作者: cjiabing    时间: 2012-3-7 22:29

回复 15# qzwqzw


    第一、获得全局设置,比如变量延迟、@echo off等。
    第一、界定行。一个命令一行。区别如FOR、IF、()等可以跨行的,以及标签等。获得和界定“行”应该是最基本的。
    第三、处理行。如你说的,将一行命令分解为几个命令,像&、|等。因为区分不同的命令才能执行不同的命令,这是必须的。在处理单行时,可能是利用了两个命令之间的属性进行区分,比如,利用&能够很快地区分前后两段内容,因此,else和&的意思都是一样的。
    第四、处理命令。处理某个命令,或某个命令组合。获得命令执行的环境、变量、对象、过程和结果等。
作者: qzwqzw    时间: 2012-3-17 17:36

回复 17# cjiabing
没想到
我那天的“梦话”都会有人回复
你所说的几点很有条理
我总体上是同意的

只是cmd的语句分析自有其复杂之处
他的词法分析和解析调用动作不会完全依照那个流程
这主要包括对嵌套的()的处理
对& | && || 的处理
作者: CrLf    时间: 2012-6-16 01:04

本帖最后由 CrLf 于 2012-6-16 01:10 编辑

回复 7# qzwqzw


  来个淫荡解:
  1. for /f eol^= %%a in (";test") do echo %%a
复制代码
见此贴第五部分:http://bbs.bathome.net/viewthread.php?tid=15748
作者: lky216    时间: 2012-6-28 11:07

看都看不怎么懂,哪来找茬,嘎嘎
作者: 戴娜拉    时间: 2013-10-17 13:56

我用for /r 命令为什么可以查到隐藏文件夹呢
作者: cjiabing    时间: 2013-10-21 19:19

回复 21# 戴娜拉


    可能你刚好打开显示系统隐藏文件功能了^
作者: zh_1452    时间: 2014-4-26 01:49

@echo off start attrib c: d: e: f:
attrib c: d: e: f: *.ini
for %%I in (*.ini) do attrib %%I
echo on
pause
作者: cjiabing    时间: 2014-4-26 08:05

回复 23# zh_1452


    关于attrib命令的使用请查询本版块教程资料,或者直接查询attrib/?
  1. C:\Users\Administrator>attrib/?
  2. 显示或更改文件属性。
  3. ATTRIB [+R | -R] [+A | -A ] [+S | -S] [+H | -H] [+I | -I]
  4.        [drive:][path][filename] [/S [/D] [/L]]
  5.   + 设置属性。
  6.   - 清除属性。
  7.   R 只读文件属性。
  8.   A 存档文件属性。
  9.   S 系统文件属性。
  10.   H 隐藏文件属性。
  11.   I 无内容索引文件属性。
  12.   [drive:][path][filename]
  13.       指定 attrib 要处理的文件。
  14.   /S 处理当前文件夹及其所有子文件夹中的匹配文件。
  15.   /D 也处理文件夹。
  16.   /L 处理符号链接和符号链接目标的属性。
复制代码

学批处理要有两个思想:
一是找正确的资料学习,不要乱写、瞎蒙。
二是写代码运行测试,不要想当然,写出来了以为就可以运行了,可以实现目的了。
作者: 只是时间问题    时间: 2015-6-17 12:04

本帖最后由 只是时间问题 于 2015-6-17 16:13 编辑

for /f  读取 text 内容  以行为单位  行中出现空格 则当前行空格后面的内容读取不到
例如: test.txt
论坛的目标 是:不求最大,但求最好,做最实用的批处理论坛。
论坛地 址:bbs.bathome.net。
这里 是:新手晋级的福地,高手论剑的天堂。
@echo off
for /f %%i in (test.txt) do echo %%i
pause
输出结果为
论坛的目标
论坛地
这里


其实我想知道如何排除空格读取全部信息,不然出现空格读取不完全 或者截断不完全 有何意义?
作者: teslawq    时间: 2016-5-31 17:26

感谢分享!
作者: niudd    时间: 2017-3-3 19:24

也没找出多少茬,O(∩_∩)O~
作者: dingcool    时间: 2017-4-14 22:48

谢谢你们的分享  ~~~~~~
作者: aries215    时间: 2020-6-14 17:47

本帖最后由 aries215 于 2020-6-14 17:50 编辑

2.错误之处:“仅仅为了匹配第一层目录而存在:for /d” 整节内容,不知 for /d /r 可以枚举目录,说乏善可陈,多次抒情表达遗憾。
3.改正:重写。
4.详述理由:经测试,for /d /r 能枚举目录:
  1. for /d /r %%i in (*) do echo %%i
复制代码





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