Board logo

标题: [原创] [教程汇总]批处理中预处理机制及其应用 [打印本页]

作者: Batcher    时间: 2009-3-18 16:44     标题: [教程汇总]批处理中预处理机制及其应用

批处理脚本高级编程技巧——变量嵌套以及预处理的优先级
http://bbs.bathome.net/thread-6537-1-1.html

预处理、变量延迟、call引出的一些问题
http://bbs.bathome.net/thread-3349-1-1.html

只用一句话能set并输出吗?
http://bbs.bathome.net/thread-1100-1-1.html

批处理常见问题解答
http://bbs.bathome.net/thread-1200-1-1.html

在变量延迟打开的情况下如何输出感叹号
http://bbs.bathome.net/thread-1962-1-1.html
  1. 预处理时对百分号%的一种处理机制
  2. 原文地址:http://bbs.verybat.org/viewthread.php?tid=10907
  3. 问题来源于我给别人写的一段代码,目的是过滤掉广告信息:
  4. @echo off&setlocal EnableDelayedExpansion
  5. for /r C:\ebook %%f in (*.txt) do (
  6.     for /f "usebackq delims=" %%i in ("%%f") do (
  7.         set "l=%%i"
  8.         set "l=!l:┌─────────────────────┐=!"
  9.         set "l=!l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=!"
  10.         set "l=!l:├─────────────────────┤=!"
  11.         set "l=!l:│更多小说下载                              │=!"
  12.         set "l=!l:│小说分享阅读,独乐乐不如众乐乐            │=!"
  13.         set "l=!l:┖─────────────────────┘=!"
  14.         echo.!l!>>"%%~nf.new.txt"
  15.     )
  16. )
  17. 有一文件C:\ebook\eg.txt内容如下:
  18. 引用:
  19. ……
  20. 师太,你竟敢跟贫道抢秃驴!
  21. (end)
  22. ┌─────────────────────┐
  23. │搜刮言情、玄幻小说!欢迎您来推荐小说      │
  24. ├─────────────────────┤
  25. │更多小说下载                              │
  26. ├─────────────────────┤
  27. │小说分享阅读,独乐乐不如众乐乐            │
  28. ┖─────────────────────┘
  29. 结果输出为
  30. 引用:
  31. ……
  32. 师太,你竟敢跟贫道抢秃驴!
  33. (end)
  34. │搜刮言情、玄幻小说!欢迎您来推荐小说      │=
  35. ├─────────────────────┤=
  36. │更多小说下载                              │=
  37. │小说分享阅读,独乐乐不如众乐乐            │=
  38. │更多小说下载                              │=
  39. ┖─────────────────────┘=
  40. 问题大致是:上一行被替换成下一行内容,且后面多了“=”。并没有达到预想的目的。
  41. 仔细思考一下可以找到原因:
  42. 以l=┌─────────────────────┐为例,经过第一次替换,变量l被清空(实际上变量名被取消定义,可以用if defined l检测◎)。
  43. 现在问题来了:在第二次替换时,即set "l=!l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=!",既然l已经不是变量,就应该被当作普通字符,而在预处理时,特殊字符!被消去,那么此时l的值应该为l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=,但l:为何不见了呢?
  44. 先看分析时用到的一个例子:
  45. @echo off
  46. set aaa=10
  47. echo %aaa:~1
  48. echo %aaa~1
  49. echo.
  50. echo %bbb:~1
  51. echo %bbb~1
  52. set aaa=
  53. echo.
  54. echo %aaa:~1
  55. echo %aaa~1
  56. echo.
  57. set bbb=20
  58. echo %bbb:~1
  59. echo %bbb~1
  60. pause
  61. 运行结果为
  62. 引用:
  63. aaa:~1
  64. aaa~1
  65. ~1
  66. bbb~1
  67. ~1
  68. aaa~1
  69. bbb:~1
  70. bbb~1
  71. 请按任意键继续. . .
  72. 看出什么不同了吗?
  73. 开始设置aaa为变量,而未设bbb,结果echo %aaa:~1的输出为aaa:~1,而echo %bbb:~1的输出为~1,字符“bbb:”直接被消去。接着取消变量aaa,结果echo %aaa:~1的输出也变成~1,字符“aaa:”也直接被消去。再接着设bbb为变量,结果echo %bbb:~1的输出变成bbb:~1,字符“bbb:”又回来了。而不管aaa、bbb是否为变量,%aaa~1、%bbb~1的输出不变。
  74. 从中可以看出预处理时对百分号%的一种处理机制:首先是百分号%被消去①,然后看%后面的字符之后有无冒号“:”,如果没有,%后面的字符被保留。如果有冒号“:”,则看%与冒号“:”之间的字符是否为已经定义的变量名,如果是变量名,则此变量名与冒号“:”都会被保留;如果不是,则%与冒号“:”之间的字符包括冒号“:”都被消去,只保留冒号“:”之后的字符。
  75. 在开启变量延迟的情况下,是用!代替%,预处理时对其处理方式与%相同。
  76. 知道这个处理机制后,就不难解释文章开关提到的问题了。
复制代码

作者: wc726842270    时间: 2010-11-28 23:04

无聊路过,顶一下,一篇不错的文章,就是看的人少的点
作者: wdhvv    时间: 2011-11-30 22:38

预处理机制 要好好研究下
作者: cjiabing    时间: 2012-2-28 23:58

回复 1# Batcher


      例子简单,解释明了,很好。不过冒号 :在这里到底扮演了什么角色还是没有说清楚。
      通常,两个变量符号(%和!)之间的变量名会被替换成变量名所指向的命令和字符,此时,变量符号和变量名都会被隐藏掉,而被变量指向的内容则呈现到屏幕上,如果内容不存在,则不显示,同时也不会回显,但不知道有没有返回码。按常见的模式看,变量符号一般是指%和!但这里的冒号似乎也有充当了类似的功能,在与!和%配对时,它也能把两者之间的字符消掉。冒号在其他地方的作用还有标签名、SET截取替换等如果是界定标签名,在句子中也用不着放标签,如果是替换,那如果把%var:~1,1%中冒号前面的var去掉了,留下的~1,1又做何用?为什么要用多一个“~”……百思不得其姐!~
作者: zhanglei1371    时间: 2013-11-8 14:59

好帖,不过例子中的去除广告的问题究竟该如何解决呢?
作者: 慕夜蓝化    时间: 2015-2-5 16:51

从另一个帖子转过来的,同样的一条命令,在后开启了变量延迟的情况下,输出正确的结果;
但在未开启变量延迟的情况下,报错,这就是预处理吗?
  1. set "var=|"
  2. echo %var%
  3. pause
复制代码
再如下:
  1. set "var=|"
  2. setlocal enabledelayedexpansion
  3. echo %var%
  4. pause
复制代码
例1在第一行添加 %1 cmd /k %0 : 可以看到报错信息。
同样的一条set "var=|" 命令,却有两条不同的结果,这个结果是由后面的代码所决定的。
预处理 = = ,解释器先扫描整个批处理脚本,如果发现语法错误,便提示报错,或者退出批处理脚本,如果一切正常,那便自上而下,逐条执行。
但预处理应该不是自上而下的,而是对当前脚本代码进行的综合分析。
作者: h1315961311    时间: 2015-2-21 16:48

我刚刚用setlocal abledelayedexpansion来延迟变量,也可以额
作者: MCRGZN    时间: 2015-8-14 00:05

说得很有道理支持!!
作者: wxyz0001    时间: 2019-11-8 00:00

本帖最后由 wxyz0001 于 2019-11-8 00:01 编辑

预处理机制的问题,可以把下面这个for循环的例子来讲述一下特殊字符的优先级
for /f "tokens=1,2" %%i in ('ipconfig /all^|find /i "Physical Address"') do set mac=%%i
当for循环的集合中两个命令间的管道符没有用^来转义成普通字符,当DOS读到这条语句后会用|管道符切割成两半,
一半是
for /f "tokens=1,2" %%i in ('ipconfig /all,
另一半是
find /i "Physical Address"')
而显然for /f "tokens=1,2" %%i in ('ipconfig /all这样的代码DOS是处理不了的。
当for循环集合中的管道符用^转义成普通字符,()括号中的代码才能成为一行语句,才能让for处理。
其他的& && || > >>同样道理。




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