批处理之家's Archiver

Batcher 发表于 2009-3-18 16:44

[教程汇总]批处理中预处理机制及其应用

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

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

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

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

在变量延迟打开的情况下如何输出感叹号
[url]http://bbs.bathome.net/thread-1962-1-1.html[/url][code]预处理时对百分号%的一种处理机制
原文地址:http://bbs.verybat.org/viewthread.php?tid=10907

问题来源于我给别人写的一段代码,目的是过滤掉广告信息:

@echo off&setlocal EnableDelayedExpansion
for /r C:\ebook %%f in (*.txt) do (
    for /f "usebackq delims=" %%i in ("%%f") do (
        set "l=%%i"
        set "l=!l:┌─────────────────────┐=!"
        set "l=!l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=!"
        set "l=!l:├─────────────────────┤=!"
        set "l=!l:│更多小说下载                              │=!"
        set "l=!l:│小说分享阅读,独乐乐不如众乐乐            │=!"
        set "l=!l:┖─────────────────────┘=!"
        echo.!l!>>"%%~nf.new.txt"
    )
)
有一文件C:\ebook\eg.txt内容如下:
引用:
……
师太,你竟敢跟贫道抢秃驴!
(end)
┌─────────────────────┐
│搜刮言情、玄幻小说!欢迎您来推荐小说      │
├─────────────────────┤
│更多小说下载                              │
├─────────────────────┤
│小说分享阅读,独乐乐不如众乐乐            │
┖─────────────────────┘
结果输出为
引用:
……
师太,你竟敢跟贫道抢秃驴!
(end)
│搜刮言情、玄幻小说!欢迎您来推荐小说      │=
├─────────────────────┤=
│更多小说下载                              │=
│小说分享阅读,独乐乐不如众乐乐            │=
│更多小说下载                              │=
┖─────────────────────┘=
问题大致是:上一行被替换成下一行内容,且后面多了“=”。并没有达到预想的目的。
仔细思考一下可以找到原因:
以l=┌─────────────────────┐为例,经过第一次替换,变量l被清空(实际上变量名被取消定义,可以用if defined l检测◎)。
现在问题来了:在第二次替换时,即set "l=!l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=!",既然l已经不是变量,就应该被当作普通字符,而在预处理时,特殊字符!被消去,那么此时l的值应该为l:│搜刮言情、玄幻小说!欢迎您来推荐小说      │=,但l:为何不见了呢?

先看分析时用到的一个例子:

@echo off
set aaa=10
echo %aaa:~1
echo %aaa~1
echo.
echo %bbb:~1
echo %bbb~1
set aaa=
echo.
echo %aaa:~1
echo %aaa~1
echo.
set bbb=20
echo %bbb:~1
echo %bbb~1
pause
运行结果为
引用:
aaa:~1
aaa~1

~1
bbb~1

~1
aaa~1

bbb:~1
bbb~1
请按任意键继续. . .
看出什么不同了吗?
开始设置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的输出不变。

从中可以看出预处理时对百分号%的一种处理机制:首先是百分号%被消去①,然后看%后面的字符之后有无冒号“:”,如果没有,%后面的字符被保留。如果有冒号“:”,则看%与冒号“:”之间的字符是否为已经定义的变量名,如果是变量名,则此变量名与冒号“:”都会被保留;如果不是,则%与冒号“:”之间的字符包括冒号“:”都被消去,只保留冒号“:”之后的字符。
在开启变量延迟的情况下,是用!代替%,预处理时对其处理方式与%相同。

知道这个处理机制后,就不难解释文章开关提到的问题了。[/code]

wc726842270 发表于 2010-11-28 23:04

无聊路过,顶一下,一篇不错的文章,就是看的人少的点

wdhvv 发表于 2011-11-30 22:38

预处理机制 要好好研究下

cjiabing 发表于 2012-2-28 23:58

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=23859&ptid=3768]1#[/url] [i]Batcher[/i] [/b]


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

zhanglei1371 发表于 2013-11-8 14:59

好帖,不过例子中的去除广告的问题究竟该如何解决呢?

慕夜蓝化 发表于 2015-2-5 16:51

从另一个帖子转过来的,同样的一条命令,在后开启了变量延迟的情况下,输出正确的结果;
但在未开启变量延迟的情况下,报错,这就是预处理吗?[code]
set "var=|"
echo %var%
pause
[/code]再如下:[code]
set "var=|"
setlocal enabledelayedexpansion
echo %var%
pause
[/code]例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

[i=s] 本帖最后由 wxyz0001 于 2019-11-8 00:01 编辑 [/i]

预处理机制的问题,可以把下面这个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处理。
其他的& && || > >>同样道理。

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.