Board logo

标题: [其他] [已解决]关于批处理BAT换行符的疑问 [打印本页]

作者: zhanglei1371    时间: 2014-4-10 23:29     标题: [已解决]关于批处理BAT换行符的疑问

本帖最后由 zhanglei1371 于 2014-4-11 14:16 编辑

问题从这两个帖子说起:
"【分享】批处理不启用变量延迟的情况下输出换行符(0A)"http://bbs.bathome.net/viewthread.php?tid=20262
和" 批处理技术内幕:预处理"http://bbs.bathome.net/viewthrea ... =%D4%A4%B4%A6%C0%ED
第一种
  1. @echo off
  2. :: ---------------- 获取换行符 0A ---------------------
  3. set NLM=^
  4. set NL=^^^%NLM%%NLM%^%NLM%%NLM%
  5. :: ---------------- /获取换行符 0A  ---------------------
  6. echo a%NL%b
  7. pause
复制代码
第二种
  1. @echo off
  2. set "n=&echo;"
  3. echo a%n%b
  4. pause
复制代码
而Batcher却说第二种是0D0A,第一种为0A,这里何解?
apang的一些解释:
如果要从字串 ab 中间换行,分成两行显示,可以这样:
  1. @echo off
  2. echo,a^
  3. b
  4. pause
复制代码
批处理内幕:^后面是三个0x0A(换行符\n的十六进制,0x0D会被丢弃掉,故不考虑它),第一个0x0A会被丢弃掉,第二个0x0A会被当成set命令参数的一部分,而第三个0x0A是分隔符,表示命令结束。所以CMD最终运行的命令是set lf=[0x0A](换行符看不见,只好这样表示。)
那么,再用set 时,为何是两个空行,而echo时只用一个空行?
另外,在开启变量延迟时,有!!号括住时,又该是几个空行呢?
【最上面的二次转义我基本理解了,但是就是echo 1个空行的地方不太理解,为何不是set的两个】
作者: Demon    时间: 2014-4-11 00:28

难得还有人学习批处理,简单回答一下吧。
  1. @echo off
  2. set "n=&echo;"
  3. echo a%n%b
  4. pause
复制代码
相当于
  1. @echo off
  2. echo a
  3. echo;b
  4. pause
复制代码
当然是0D0A
作者: Demon    时间: 2014-4-11 00:35

至于一个空行还是两个空行的问题,把代码改一下你可能就明白了。
  1. @echo off
  2. echo,a^
  3. b
  4. pause
复制代码
输出
  1. a
  2. 'b' 不是内部或外部命令,也不是可运行的程序
  3. 或批处理文件。
  4. 请按任意键继续. . .
复制代码
多一个空行就多一个0x0A,而0x0A属于批处理中的分隔符,所以把命令截断了,于是CMD在解析时认为b是一条命令,但是找不到该命令,故报错“'b' 不是内部或外部命令,也不是可运行的程序”。而截断命令是在set中我们要追求的结果,所以要用两个空行。
作者: CrLf    时间: 2014-4-11 03:52

补充一句,对 % 的解析发生在语法解释之前
其余同上

有兴趣的话,往这看:
http://bbs.bathome.net/viewthread.php?tid=6692
http://bbs.bathome.net/viewthread.php?tid=18351
http://bbs.bathome.net/viewthread.php?tid=12891
作者: zhanglei1371    时间: 2014-4-11 09:26

回复 3# Demon


    谢谢,两行和1行的问题,我知道了。但是第一个0D0a的地方还是不知怎么回事。二楼的解释我之前也知道是这么回事,因为都是这样分成两行,但是分成两行后怎么知道其后面的是回车+换行符,而
  1. ^
  2. ...
复制代码
中的却是换行,而不是回车+换行?
我的理解:是否只要在set中,^号后面假如有回车+换行符时,就如预处理文章中所说的那样,回车就直接被舍弃掉了,仅剩下换行符,因此,此时不涉及回车符,仅有换行符在进行操作?
不知这样理解是否正确,还望明示。
作者: Demon    时间: 2014-4-11 12:45

echo命令输出字符的时候会在后面自动加上0D0A,这应该是常识吧。
  1. @echo off
  2. (echo a
  3. echo;b)>1.txt
  4. (echo a^
  5. b)>2.txt
  6. pause
复制代码
用十六进制编辑器打开1.txt和2.txt,内容分别是

61 0D 0A 62 0D 0A

61 0A 62 0D 0A

你的理解并不正确,批处理在进行词法分析的时候是会忽略掉0x0D的,与命令无关。
作者: zhanglei1371    时间: 2014-4-11 14:15

回复 6# Demon


    多谢指点,基本明白些了。现将开头的获取0A的部分解释下,有不对的地方,还请批评指正!
  1. :: ---------------- 获取换行符 0A ---------------------
  2. set NLM=^
  3. ::这里NLM已经是一个换行符了,可以用echo a!NLM!b查看效果,但是%NLM%却仍为空【不知为何】。
  4. set NL=^^^%NLM%%NLM%^%NLM%%NLM%
  5. ::这里这样理解:先替换%%中的东西:变成(^^)(^换行符换行符)(^换行符换行符)[其实上面的NLM就是1个换行符,加括号方便说明]
  6. ::经过预处理,变成:(^)(换行符)(换行符),到这里恰好和上面set NLM=的内容相一致
  7. :: ---------------- /获取换行符 0A  ---------------------
  8. echo a%NL%b
  9. ::这里先替换:变成a(^)(换行符)(换行符)b,预处理一次:将第一个换行符干掉,留下第二个。就是最终结果了。
  10. pause
  11. REM ========代码区===========================
复制代码





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