Board logo

标题: 批处理中得到回车符和换行符 [打印本页]

作者: zqz0012005    时间: 2009-12-12 13:48     标题: 批处理中得到回车符和换行符

  1. @echo off
  2. for /f "delims=" %%a in ('ipconfig^|findstr /i "Address"') do set var=%%a
  3. setlocal enabledelayedexpansion
  4. set CarriageReturn=!var:~-1!
  5. rem 必须用!!的形式才能得到和输出回车符Cr,否则回车符会被丢弃
  6. echo +++!CarriageReturn!---
  7. rem 验证
  8. echo +++!CarriageReturn!---|find /v ""
  9. rem 用%%输出,得不到回车符
  10. echo aaa%CarriageReturn%bbb
  11. echo aaa%CarriageReturn%bbb|find /v ""
  12. rem :::::::::::::::::::::::::::::::::::
  13. rem 换行符Lf,也必须用!!的形式才能输出,否则Lf后面的字符被丢弃
  14. set NewLine=^
  15. rem :::::::::::::::::::::::::::::::::::
  16. rem 上面两行直接回车
  17. rem 虽然文本中转义字符^后面是CrLf两个控制字符,但它们在预处理时(执行语句之前)
  18. rem 被作为行结束符(Tip:批处理是按行(整行)读取)
  19. rem 因此实际运行时此行中^后面没有字符了,^是对文本中下一行的字符进行转义
  20. rem set语句一下行是CrLf两个控制字符,按理说^应该是对Cr转义,从而NewLine应该是CrLf两个字符。
  21. rem 但下一行还需要一个空行才能结束语句,说明这一行的Lf没有行结束的作用。
  22. rem 所以如果^是对Cr转义,则Lf应该仍然是原来意义上的控制字符,有行结束的作用。
  23. rem 则set语句在这一行就结束了,不需要下一行的空行,所以应该Lf是被转义了。
  24. rem 而Cr被抛弃了,NewLine确实只有一个字符Lf而不是Cr,更不是两个字符CrLf
  25. rem Cr的被抛弃看来也要归功于预处理(直接在CMD中输入时也要两个空行)。
  26. rem 再次体现了MS瘟到死使用CrLf两个字符作为行结束符的不统一、不和谐之处!
  27. rem Linux只需一个空行就够了
  28. rem $echo \
  29. rem $(回车)
  30. rem $(这一行就得到结果了)
  31. rem :::::::::::::::::::::::::::::::::::
  32. echo 000!NewLine!111
  33. rem 用%%输出,得不到换行符
  34. echo aaa%NewLine%bbb
  35. echo aaa%NewLine%bbb|find /v ""
  36. pause
  37. rem 此时的回车换行符没有表示输入完成(行结束EOL)的作用,只相当于普通字符
  38. set/p=CrLf!CarriageReturn!!NewLine!
  39. rem 用%%输出,回车换行符都得不到
  40. set/p=CrLf%CarriageReturn%%NewLine%
  41. rem '\r', 1 byte
  42. set/p=Cr!CarriageReturn!<nul>Cr.txt
  43. rem '\n', 1 byte
  44. set/p=Lf!NewLine!<nul>Lf.txt
  45. rem "\r\n", 2 byte
  46. set/p=CrLf!CarriageReturn!!NewLine!<nul>CrLf.txt
  47. pause
  48. del Cr.txt Lf.txt CrLf.txt
复制代码
包含换行符Lf的字符串交给 for /f 解析时,会将字符串理解为多行文本。
作者: zqz0012005    时间: 2009-12-12 13:55     标题: 题外话:

越来越感觉到MS瘟到死的不爽了
只说说转义字符
在bat中是^(及%对百分号自身转义时)
findstr中是\
而find中没有转义字符,但需用"对引号自身转义
reg命令用\对引号转义,但路径中的\不需(不能)转义
而注册表文件中的\就完全是标准的转义字符
vbs中用"对引号自身转义
WMI(WQL)中的\,有时要用\对其转义,有时不要
        wmic datafile where (drive='c:' and path='\\' and filename='boot') get name
        wmic process call create "C:\windows\notepad.exe"
js中转义字符显然又是标准的\
……
完全没有个准儿。。。
只能说Windows是个无敌的混乱魔王。。。
作者: zqz0012005    时间: 2009-12-12 14:01     标题: 再题外话:

还是看Windows不爽。。。
既然提到findstr,就再说说。
不必说findstr的正则表达式太鸡肋,也不必说findstr的诸多Bug,
单说findstr将单词边界符\b分为\<和\>有何意义?
特意增加书写时的复杂性?就像QWERTY键盘故意设计成混乱排列?
还是有什么典故吗?我记得以前用过某软件好像也是这样的方式。
如果是典故还望知悉者相告。

PS:最近开始接触Linux
作者: neorobin    时间: 2009-12-12 20:22     标题: 有空再好好研究下你说的问题

我做的一个自动连接宽带的小工具在分析 ipconfig 的输出时为了得到 网卡地址, 本打算也是用的 !! 和字符串后段截取, 结果遇到了 包含 CR 和或 LF 的问题, 懒得深研究它, 就改了方法从前面截取了, 有空真要再好好看看你这个, 也把这个问题更深入了解一下.
作者: zqz0012005    时间: 2009-12-12 21:43     标题: 再记一笔

以前某大提到findstr的一个技巧性应用:
findstr $ 判断一个文本最后一行是否以回车换行结束。

但现在发现findstr的$只匹配含有回车符\r的行,即以\r或\r\n结尾的行。
没有\r时,即使有\n也不能匹配。而Linux格式的文件都是\n结尾的。

看看vbs/js中的正则是怎么说的:
“如果设置了 RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。”
因为Cr、Lf一般即表示换行,所以对按行处理文本的程序(如sed、findstr)来说,显然都相当于设置了Multiline 属性。
findstr不能匹配'\n'之前的位置,是再次缩水。。。
作者: zqz0012005    时间: 2010-1-12 19:55     标题: 再记一笔

  1. (set/p=Batcher|findstr $)<nul
  2. cmd/c"set/p=Batcher<nul"|findstr $
复制代码
set /p 的输出明明没有回车,findstr为什么能找到$?

验证这种形式没有回车:
http://www.bathome.net/viewthrea ... amp;page=1#pid39007
作者: sysplay    时间: 2010-1-13 11:15

  1. @echo off
  2. for /f "delims=" %%a in ('ipconfig^|findstr /i "Address"') do set var=%%a
  3. setlocal enabledelayedexpansion
  4. set CarriageReturn=!var:~-1!
  5. echo +++!CarriageReturn!---
复制代码

这里为什么输出结果是---,
如何实现输出结果为
+++
---
作者: zqz0012005    时间: 2010-1-13 12:22

1、为什么,建议楼主百度一下以了解回车符和换行符的概念。
2、如何,代码中这句的下一行就是
作者: 523066680    时间: 2010-1-13 12:35     标题: 回复 3楼 的帖子

1.果然前辈有学Bash ,就是感觉有代沟,不敢根你交流。而且我刚入门。
   bash中很多东西很严格很标准,感觉很好。
   上次硬挑骨头: read -n 字符个数  ,结果回车就结束输入了,读的没有N个字符,哈哈。
                    而 read -t  是严格到指定时间结束,回车也被吃进去的。

2.我是因为windows老是变卦,记下的"字符" 不知道何时就不能用了。
所以决定去学习下linux的东西。

3.帖子浏览下来,前辈学习的很深入,佩服了。


关于7楼的问题,我想根刚接触电脑时的知识定向有关,我一直以为回车就是回车。
那是一个字符, 并不知道回车换行是两回事。 直到现在也不算清楚他的概念。
只知道区分的话:一个字符负责回到行首,一个字符负责转行。
于是那个代码的输出是: 1,显示 +++   2 ,回到行首 3,打下  ---   
所以你看到的是---


--------------------------------------------------------------------------------
对了  把那个代码的 +++改成 ++++  
也就是 echo ++++!CarriageReturn!---  
如果不了解回车换行的话,那个结果会觉得挺有趣的。


话说《深入挖掘windows脚本技术》 那篇有个下载文件vbs的,就是利用回到行首的字符
来在cscript 的某一行中实现 进度条滚动 动画的

[ 本帖最后由 523066680 于 2010-1-13 13:18 编辑 ]




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