标题: [特效代码] 批处理中的冒号消隐与标签重叠 [打印本页]
作者: cjiabing 时间: 2012-2-28 00:52 标题: 批处理中的冒号消隐与标签重叠
那么晚了,crlf还在啊,响应你号召我整理下!~
——————————————————————————————————————————————
第一、冒号隐身术
我们通常认为,冒号在批处理中的主要作用就是标记标签,并兼做标记注释(标签文本化功能)。但在特定情况下,比如变量延迟情况下,冒号会产生一些特殊的作用。
大家看下下面的例子,重点看“!第一个!、:第二个:、%第二个变种:”这三句,这三句都没有在批处理运行时将结果显示到窗口。其中,“!第一个!”是一个合法的变量名,因为前面没有“set 第一个=XX“,所以,这个变量名就是空的,当然不显示了。第二个可能你还说得通,把它当做一个特殊的标签,这种标签是存在的,我在其他帖子里有介绍。最关键的还是第三个“%第二个变种:”,它既不是变量名,也不是标签名,但它就是不见了,这是为什么呢?- @echo off&setlocal enabledelayedexpansion&title 冒号之问!~
- echo;
- echo;
- echo; 1、如果你在这里看见证明你的神性比往日已经有了许多的进步……
- echo; 2、但我要做一件事,让你知道你的智慧仍然无法与诸神相媲美……
- echo; 3、!如果你已经看见我给你传达的智慧,那么我将让你大开眼界:&pause
- echo;
- echo; 4、现在,我想问你,你看见第三句了吗?
- echo; 5、是的,你没有仔细看,那么,我们来两个故事吧……&pause
- echo;
- set str=!我潜心向神学习智慧之道!
- echo; 1)!str!【%str%】为什么值为空呢?因这个变量“^!我潜心向神学习智慧之道^!”没有SET。
- echo;&pause
- echo;
- set var=!神啊救救我吧:
- echo; 2)%var%【!var!】:var:【!var:】这里又是为什么变空了呢?&pause
- echo;
- echo; 6、我们继续举一反三,请看代码和运行效果,不解释……&pause
- echo;
- echo;
- !这样你能看见我吗?:
- !第一个!
- :第二个:
- %第二个变种:
- echo;
- echo; 7、以下可能无法成功执行!~&pause
- echo;
- 第三个!
- 第四个:
- !第五个
- :第六个
- echo;
- pause
复制代码
这是为什么呢?我们再来看,导致我今天找出答案的例子:- @echo off
- set "Symbol= !#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""
- echo;"%Symbol%"
- ::这里有一对百分号,所有字符显示完整。
- pause
- @echo off
- set "Symbol= !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""
- echo;"%Symbol%"
- ::这里去掉了一个百分号,这段“%%&'()*+,-./0123456789:”被消失了!~
- pause
- @echo off&setlocal enabledelayedexpansion
- set "Symbol= !#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""
- echo;"%Symbol%"
- ::这里启用了变量延迟,两个百分号,这段“!#$%&'()*+,-./0123456789:”被消失了!~
- pause
-
- @echo off&setlocal enabledelayedexpansion
- set "Symbol= !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""
- echo;"%Symbol%"
- ::这里启用了变量延迟,一个百分号,这两个“#$”变回来了,但“%&'()*+,-./0123456789:”仍然没见。
- pause
-
- @echo off&setlocal enabledelayedexpansion
- set "Symbol= !#$%%&'()*+,-./0123456789;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~":"
- echo;"%Symbol%"
- ::如何处理?把叹号放在前面,冒号放在后面,结果,全不见了!~看来,问题就在叹号和冒号之间,在百分号与冒号之间。实际上,可能是冒号在这里扮演了一个配对变量的角色——在变量延迟的情况下,在变量名不完整的情况下,冒号会自动补上变量,使之成为真正的变量——乱猜的,。
- pause
复制代码
这里再引用试验代码,检查变量与标签之间的关系,检查!、%、:三者之间的关系。- @echo off
- set eee=我爱北京天安门!
- !aaa:
- ::在变量延迟的情况下,这里也会消失。
- echo !bbb:
- echo %ccc:
- ::这里的变量消失了!~
- echo %eee:
- ::奇怪的是这里的eee没有消失!~看来与变量无关啊?
- echo %%ddd:
- call :!%ccc:123!
- pause &cls
- echo;
- call :%ccc%:123
- pause&exit
- :!123!
- echo;
- echo; 春天回来了,你也会回来吗?
- echo;
- goto :eof
- :123:%ccc%:123:%ccc%:123:%ccc%:123:%ccc%:123:%ccc% :123标签只是单纯的文本,并且只支持findstr /b功能,让在标签上的代码都失去了命令意义。
- echo;
- echo; 抽刀断水水更流,举杯销愁愁更愁!~
- echo;
- goto :eof
复制代码
由上可见,!var:也得,%var:也得,它们与之间存在一定的关系!~再看:- @echo off
- set v=1234
- echo %!v:123
- pause
复制代码
其他可能与此有关的一些问题:http://www.bathome.net/viewthread.php?tid=11887
再引用10年的一个例子,我一直搜藏着:- @echo off
- for %%i in ( 我爱,北京?天安门) do echo %%i
- for %%a in (8,"link":"\/index.php?mod=profile&u=c265e4bd629300c5c7f3fe500658b4b038e55da5399c45ba",-) do echo %%a
- pause
- 以逗号为分隔符
- 补充:
- 有此对网页内容进行编辑,发现一个无法读取的问题,经分析如下:
- 1、for %%a in ( 我爱,北京?天安门) do echo %%a
- 2、for %%a in ( 我爱,北京天安门) do echo %%a
- 上例无法显示,下例可以正常显示。有此可知,英文状态下的问号在字符串中有通配符的意义,但干嘛跑这里来意义呢?
复制代码
第二、标签的范围与标签重叠
标签可能是一个区功能化的文本区,因为放在标签中的任何字符(><另外再考虑)都不会发生命令功能,也就是,你在标签中插入一个del命令,它根本不执行。另外,crlf提示,一个完整的标签功能区是(0,512)的范围,超出这个范围就是另起一行,因此,我们可以用其他字符填满标签511个字符,然后紧接着后面513位置接其他命令,这时,命令可以执行了,这正说明了标签的范围大小。由以下例子可知,标签虽然是长长的一行,但实际上在达到512时标签已经自动换行了,所以,此时命令可以接上去。- cls&title 标签之问!~:: by cjiabing from 批处理之家 http://www.bathome.net&title 批处理标签重叠大法
- echo;
- call :1111
- ::这是正常标签引用
- pause
- echo;
- call :2222
- ::在标签前后添加了一些字符,但标签仍然发生作用
- pause
- echo;
- call :3333
- ::你会发现,原来标签的末尾真的有尾巴,这个尾巴是一行511字符,513字符后是另外一行——可以拼接另外一组命令,甚至另外一个标签。
- pause
- echo;
- echo;
- set 4444=511513
- echo;
- call :4444
- ::演示稍微复杂的标签与命令的连接。
- pause
- echo;
- echo;
- set num=0
- call :5555
- ::在这一长长的行中,你会发现两个标签,一个是:morel,另外一个是:look,这里先执行第一个标签。
- pause
- echo;
- echo;
- echo; ★ 注意:这是第二次运行!~
- echo;
- call :6666
- ::为了证明这个是第二个标签,特地在前面加了个识别“try”,你会看到,第二个标签引用的段落与第一个是一样的。
- pause
- echo;
- echo; 如果没看清楚我们再来一遍!~
- echo;
- pause&cls
- call :5555
- pause
- call :6666
- pause
- exit
-
- :1111
- echo;
- echo; 一、我爱批处理
- echo;
- goto :eof
-
- :====2222 iloveyoubaby
- echo;
- echo; 二、请注意观察标签“2222”前后。
- echo;
- goto :eof
- :3333 adiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyou dir/b
- echo;
- echo; 三、请找到dir命令所在的位置!~
- echo;
- goto :eof
-
- :4444 iloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubayiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyix[!511!]echo;Hello&for /l %%a in (1,1,10) do echo %%a
- echo;
- echo; 四、可以在标签末尾【511列之后】放置命令,命令可以组合。
- echo; 注意空格不能少,中文可能不支持。
- echo;
- goto :eof
-
- :5555 iloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirlovde echo;first :6666 iloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyiloveyoubabyiloveyoubabydirloveyoubabyilove
- echo;
- set /a num+=1
- echo; 五、两个标签共一行,执行两次,现在第 【!num!】 次!~
- echo;
- echo; 标签重叠——见过一行里有两个以上的标签吗?
- echo; 本段代码有两个标签:5555和:6666,而且每个标签都会发生作用!~
- echo; 从此以后,你可以大声说,你也可以用一行两个标签来执行命令了!~
- echo;
- echo;
- goto :eof
复制代码
这个标签不是简单地接就可以了,你可以在第一个标签的最后加一个命令,然后下一个标签,又接一个命令……如:
able1 …………511 echo;hello& :Lable2 …………1030 echo;I am here & Lable3…………
这样,你就可以把所有命令拼接在一行里实现,即使有标签都可以如此制作。
作者: CrLf 时间: 2012-2-28 03:07
标签被调用时,一次性只读取 512 字节这个倒是第一次知道,看来预处理中还有不少彩蛋,学习了
作者: CrLf 时间: 2012-2-28 03:37
顺便说一下,那个 !str: 其实是...以前在贴吧看到有人问,还是发个链接吧:
http://tieba.baidu.com/p/1020906001
注:此贴中一头猪是扮猪,还有一个美女是斑竹,一只猫是吧猪,剩下两个没有脸的都经常发炎,尤其是那个头像比较绿的人技术很好...
嗯,你懂得,我什么都没说。
作者: cjiabing 时间: 2012-2-28 06:03
回复 3# CrLf
你好幽默呢!~整理了一下,有许多想说的,又有许多想试验的,天亮了再说!~
作者: ivor 时间: 2012-2-28 09:45
细看才发现这不就是变量替换吗?set /?里面的功能
作者: powerbat 时间: 2012-2-28 19:25
http://www.bathome.net/thread-3768-1-1.html
从中可以看出预处理时对百分号%的一种处理机制:首先是百分号%被消去①,然后看%后面的字符之后有无冒号“:”,如果没有,%后面的字符被保留。如果有冒号“:”,则看%与冒号“:”之间的字符是否为已经定义的变量名,如果是变量名,则此变量名与冒号“:”都会被保留;如果不是,则%与冒号“:”之间的字符包括冒号“:”都被消去,只保留冒号“:”之后的字符。
在开启变量延迟的情况下,是用!代替%,预处理时对其处理方式与%相同。
转自verybat,其实还有一篇文章就是专门讲%与:的关系。
verybat对变量机制的研究非常深入透彻,当时xzyx、zqz0012005等人写了很多理论分析的文章,可惜verybat突然关闭了,都没来得急收藏。
作者: cjiabing 时间: 2012-2-28 23:00
回复 6# powerbat
描述是准确的,但仍然没有揭示原因,所以不能说是深刻。
第一个冒号的作用我仍然不明就里,第二个标签还是比较好理解的。
这个问题稍微复杂一些,我一时半会描述不清楚,大家一起讨论了。
作者: qzwqzw 时间: 2012-3-21 18:15
确实讨论的问题有点多且杂了
百分号和冒号的问题确实如5楼所说
是变量扩展时的替换和截取特性所带来的问题
setlocal DISABLEEXTENSIONS禁用了命令行扩展之后
这个问题就没有了
当然会带来其它一些问题
10年前的那个案例
记得曾有专贴讨论过
在for的遍历集里出现? 和 *
必然会被当作文件集进行匹配
因为它们是文件通配符
否则被当作普通字符串进行匹配
这个特性似乎没什么好争议的
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |