[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[其他] [讨论]批处理中特殊字符的解释机制探索

本帖最后由 applba 于 2011-5-20 03:46 编辑

回避了预处理这个概念。

把解释过程了分成了两个阶段,第一轮和第二轮。

第一轮解释
这一轮的解释是全局性的,是无条件的,是发生语句执行前的。
解释的符号有(% ^ ")。
关于这三个符号的优先级问题(即先解释哪个):
%具有最高优先级,^和"具有并列的优先级。(谢谢QZWQZW的指正)
意思就是说所有的%的处理完毕后才开始处理^和";而对于^和",哪个在前面就先处理哪个

第二轮解释
是局部性的,是由具体的命令或语句进行的,一边运行一遍解释。
解释的符号比较多:
通用特殊符号:括号() & && | || > >> < ,如果开启了变量延迟包括解释!及其范围的^
专用特殊符号:各命令自行识别的特殊符号,差别可能很大。如大多数命令都把空格识别为分隔符,echo把它识别为普通符号。
优先级问题:这些特殊符号哪个在前面就先处理哪个,前面的先处理,后面的后处理。
几个符号作用范围: 管道符号(|) 不能超越 输入输出重定向符号(< > >>) 不能超越 命令分隔符(&,&&,||) 不能超越 括号。

call 触发的对%和^的再次解释
即call命令运行时把^和%重新识别特殊字符,并再次启动解释。
call每嵌套一次,都会把%和^ 重新识别为特殊符号,并启动新一轮的解释。
3

评分人数

为什么不回过头来想想39楼提到的优先级呢?
powerbat 发表于 2011-5-20 20:52

我认为连接符(包括管道)是平级的,而非“| > & > && > ||”

TOP

为什么不回过头来想想39楼提到的优先级呢?

TOP

52# applba


话也不能这么说呀,这几天的争论中,我虽然一再否定自己原先的观点,但是并非意味着失败,而是由此越来越趋近于预处理机制的核心真相...这种争论,虽然有很多东西无从论证,但是总归是有助于相互印证的,毕竟要想一个人去揣测出所有方面的机制是很难的。很喜欢这样相互切磋,技术论坛,就应该有这种气氛

TOP

51# zm900612


唉……我也不想这样啊……看来我以后还是老实写点批处理代码……这些东西想了也是白想,还不实用

TOP

50# applba


那就用重定向的优先级低于管道来解释不是豁然贯通了吗?为什么要把他们强凑在一个优先级上,再打上一堆补丁去弥补这个看法的漏洞呢?

TOP

48# qzwqzw


不能超越,我的意思就是前者会受到后者的限制。
echo 123&echo 456 >nul
上面例子中,>的作用范围受到了&的限制,>只能对echo 456重定向,不会对echo 123重定向。

TOP

46# qzwqzw

|  > >> < & && ||
这几个特殊符号肯定是在执行时进行功能解读的,前四个都涉及到句柄,后三个都必须等待前面的命令执行完毕。

你的说法也合理:即这几个符号那个在前面就先处理哪个,前面的先处 ...
applba 发表于 2011-5-20 00:48


|是兼具句柄重定向和语句连接符功能的,而且具有连接符所有特征,所以不能将它和重定向符号并列起来。我举个例子
  1. (dir >1.txt >con)>2.txt
  2. ::重定向符号是并列的,但是每一次重定向都会刷新对应句柄的设置,所以对同样的句柄,只有最后一次重定向是有效的。
  3. set|findstr /i "pro"|sort +2
  4. ::而管道则不光将两个命令的0、1句柄桥接起来,还充当了语句之间的连接符,连接符的特征是按从左到右的顺序进行判断,举个例子:
  5. 2>nul ren %~s0 &&(echo 1,此处不显示)||(echo 2,此处显示)&&(echo 3,此处显示)||(echo 4,此处不显示)
  6. ::可见语句的优先级顺序就是连接符的优先级顺序,连接符是并列的,而且优先级高于重定向符。
  7. pause
复制代码

TOP

本帖最后由 qzwqzw 于 2011-5-20 08:25 编辑

所谓的“不能超越”不能理解
不需要把概念搞的这样理论化
天的白色影子

TOP

本帖最后由 applba 于 2011-5-20 01:28 编辑

46# qzwqzw

|  > >> < & && ||
这几个特殊符号肯定是在执行时进行功能解读的,前四个都涉及到句柄,后三个都必须等待前面的命令执行完毕。

你的说法也合理:即这几个符号那个在前面就先处理哪个,前面的先处理,后面的后处理。这样的话就存在一个作用范围的问题: 管道符号(|) 不能超越 输入输出重定向符号(< > >>) 不能超越 命令分隔符(&,&&,||) 不能超越括号。

TOP

37# applba
  1. set "a=10f611|findstr f6"
  2. echo %a% & echo string
  3. pause
  4. echo test1234 > test.txt
  5. find "test" < test.txt | find "1234"
  6. find "test" | find "1234" < test.txt
复制代码
这个例子也许不太好
我只是想说
& | < 谁先解释取决于谁在命令行之前
以及相应的功能逻辑

这与%不同
即使在命令行末尾
也会被先行扩展
天的白色影子

TOP

猜想CMD把for /L 语句转换为C语言是类似这样的:
for /l %a in (start,step,end) do ...
==>
int i = 0;
int iStart = getenv("start");//假设for /L 的三个值都是变量
int iStep = getenv("step");
int iStop = getenv("end"); //在执行for之前已经把条件都确定了
for (i = iStart; i < iStop; i += iStep) {...} //在循环体中再怎么改变start,step,end,已经不影响for的条件了
1

评分人数

TOP

本帖最后由 powerbat 于 2011-5-20 00:24 编辑

'%' >> '^' > '()' > '>、>>' > | > & > && > ||
这个优先级应该没什么问题(当然我也没详细测试过)

set n=3&for /l %%a in (1 1 !n!) do ... //可以
set n=1&for /f "tokens=!n!" %%a in (循环集) do ... //不行
前者可以用延迟变量,说明for条件是在for命令被cmd执行时计算。而循环体中不能改变变量,则说明for计算条件只是在执行循环体之前处理一次。
后者可以认为是for /f 内部处理引号“从句”时,对tokens处理很简单,发现传给它的值是非数字就报错,没考虑值是变量的情况。

if的条件本来就只判断一次,何来改变?况且if的条件可以用延迟变量,说明if条件在预处理后还可以在if被cmd执行时才计算。
说for和if是“关键词”,因为它可以引导语句块。
其实不使用它们,单独用()把一组语句括起来,也是语句块,比如:
(echo a
echo b)>a.txt

TOP

以前不是有人说过for和if是“关键词”吗?

set n=3&for /l %%a in (1 1 !n!) do ...
是没问题的。
set n=3&for /l %%a in (1 1 !n!) do (... if %Got%==1 (set n=10) ...)
在循环体中改变循环条件是不行的。
powerbat 发表于 2011-5-19 22:24

如果for和if是语块这个命题成立,那么条件语句将是语块的一部分,而非语句的一部分,这就可以解释为什么在语块中无法重新定义for和if的条件语句了,因为它们的条件语句是和整个语块一起被预处理的

TOP

以前不是有人说过for和if是“关键词”吗?

set n=3&for /l %%a in (1 1 !n!) do ...
是没问题的。
set n=3&for /l %%a in (1 1 !n!) do (... if %Got%==1 (set n=10) ...)
在循环体中改变循环条件是不行的。

TOP

返回列表