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

[其他] 为什么开启延迟变量扩展需要两个^^!转义!字符,而不开只是一个^,转义!字符

本帖最后由 GNGW 于 2024-3-20 16:04 编辑

起因是因为一串代码,我在论坛上看到的,原帖地址http://bbs.bathome.net/viewthread.php?tid=15680
  1. set str=!我潜心向神学习智慧之道!
  2. echo;        1)!str!【%str%】为什么值为空呢?因这个变量“^!我潜心向神学习智慧之道^!”没有SET。
复制代码
这是源代码,我发现“!我潜心向神学习智慧之道!”这句话并没有显示,碎片记忆中想加个^试试,于是改成了这样
  1. set str=!我潜心向神学习智慧之道!
  2. echo;        1)!str!【%str%】为什么值为空呢?因这个变量“^^!我潜心向神学习智慧之道^^!”没有SET。
复制代码
成功显示,联系到很多地方都需要用双字符,在我的上篇帖子中:http://www.bathome.net/redirect. ... 8649&pid=279265,又好奇为什么本身使用^脱字符,就可以转义特殊字符了,为什么还要加一个^脱字符将后面的脱字符进行转义为普通字符,才能显示“!我潜心向神学习智慧之道!”呢?根据这一原因,进行了深入的研究,提问,发现在说,脱字符,这个问题跟到这,阅读了部分帖子,发现一个逻辑或者机制,或者说理解,^与任何字符在一起此字符都是普通字符,在开启延迟变量后,特殊符号!需要两个^^才转化成普通字符,我想这和延迟变量扩展机制有关,有没有大佬普及科普一下。

尽量发完整代码,代码较长不必重复贴码,贴出原帖地址
代码中应该遗漏了 setlocal enabledelayedexpansion 吧
1

评分人数

    • GNGW: 乐于助人技术 + 1
bat小白,请多指教!谢谢!

TOP

回复 2# 77七


    原帖地址http://bbs.bathome.net/viewthread.php?tid=15680

TOP

开启延迟变量扩展后,引号内的的特殊字符也会被处理,如果语句中有含有!则会再进行一次“预处理”。
“^!我潜心向神学习智慧之道^!”第一次“预处理”去掉脱字符,第二次扩展变量,
“^^!我潜心向神学习智慧之道^^!”第一次去掉一个脱字符,第二次转移!
1

评分人数

    • GNGW: 乐于助人技术 + 1

TOP

本帖最后由 GNGW 于 2024-3-20 15:58 编辑

回复 4# buyiyang


    可以详述一下机理吗大佬可以说一下,去掉脱字符的原因吗?我发现预处理这种情况和双符号的情况,都会去掉一个符号,这是为什么?什么机理?

TOP

转义不是在命令解析阶段转义的 , 而是在延迟拓展阶段解析时进行的转义

要转义! , 就是^! ,但这只是延迟拓展阶段内的 , 在延迟拓展阶段之外 , ^也是一个特殊字符 , 也需要转义
换句话说 , 你需要的是一个延迟拓展阶段的^!来供延迟阶段解析时转义成! , 还得对^!中^再次进行转义

^^!经过命令解析变成^!
^!经过延迟拓展解析变成!

这东西需要了解cmd的解析规则 , 可以参考
https://stackoverflow.com/questi ... pts/4095133#4095133
1

评分人数

    • GNGW: 这个帖子是一个缺口,目前为止深入技术的帖 ...技术 + 1

TOP

本帖最后由 GNGW 于 2024-3-21 11:34 编辑

回复 6# Five66


    这个帖子中关于
If the command token begins with :, and this is the first round of phase 2 (not a restart due to CALL in phase 6) then
The token is normally treated as an Unexecuted Label.
The remainder of the line is parsed, however ), <, >, & and | no longer have special meaning. The entire remainder of the line is considered to be part of the label "command".
The ^ continues to be special, meaning that line continuation can be used to append the subsequent line to the label.
An Unexecuted Label within a parenthesized block will result in a fatal syntax error unless it is immediately followed by a command or Executed Label on the next line.
( no longer has special meaning for the first command that follows the Unexecuted Label.
The command is aborted after label parsing is complete. Subsequent phases do not take place for the label
There are three exceptions that can cause a label found in phase 2 to be treated as an Executed Label that continues parsing through phase 7.
There is redirection that precedes the label token, and there is a | pipe or &, &&, or || command concatenation on the line.
There is redirection that precedes the label token, and the command is within a parenthesized block.
The label token is the very first command on a line within a parenthesized block, and the line above ended with an Unexecuted Label.
The following occurs when an Executed Label is discovered in phase 2
The label, its arguments, and its redirection are all excluded from any echo output in phase 3
Any subsequent concatenated commands on the line are fully parsed and executed.
For more information about Executed Labels vs. Unexecuted Labels, see https://www.dostips.com/forum/vi ... &p=55405#p55405
这一段中给出的链接并没有解答^脱字符的完全原理,同时并没有解开我的疑惑 (再次讨教)https://stackoverflow.com/questi ... pts/7970912#7970912

只有这一小段,解释了解释器在开启延迟变量拓展之后的扫描过程,去掉^脱字符,但对于,后面^! 作为普通字符之后,没有详细描述对^!第一个^脱字符的处理。
No change is made to tokens that do not contain !.

For each token that does contain at least one !, scan each character from left to right for ^ or !, and if found, then

5.1 (caret escape) Needed for ! or ^ literals
If character is a caret ^ then
Remove the ^
Scan the next character and preserve it as a literal
Continue the scan
吹毛求疵的人,找问题的人,好奇心强的人,动手能力强的人,虚心的人,以及一个简单的研究技术的人。

TOP

呃 , ^就是bat中的转义符 , 但是转义没说只会转义1次 , 也就是说可能会转义2次 , 3次 ,甚至4次 ....
就像xxx表示1个反斜杠(\)时 , 需要8个反斜杠(\\\\\\\\) , 这期间转义了3次反斜杠

这也意味着需要了解规则了解流程 , 掌握流程中那些是需要转义的 , 转义了的多少次

开启延迟变量后 , 两个!包围的会变成变量 , !有了特殊作用 , 这很明显!是需要转义的 (因为要表示!本身) ,
单纯的输出! , 流程总共expansion了2次 ,因此会有2次转义

TOP

本帖最后由 GNGW 于 2024-3-21 17:15 编辑

回复 8# Five66


    但是这个上面没有说明流程走了两次,进行了两次扩展。我的意思是没有任何的证明.....能够证明转义了两次,在没有证明或验证的情况下,任何的猜测都有可能是错的。
吹毛求疵的人,找问题的人,好奇心强的人,动手能力强的人,虚心的人,以及一个简单的研究技术的人。

TOP

回复 9# GNGW


    啊???6楼连接里的Phase 2)跟Phase 5)不就是了???  echo语句的话 正好2个
就算没说明 , 自己根据步骤模拟一下代码的解析和执行流程不就行了

TOP

回复 10# Five66


    噢噢,看到了。“自己根据步骤模拟一下代码的解析和执行流程不就行了”这个要怎么执行?
吹毛求疵的人,找问题的人,好奇心强的人,动手能力强的人,虚心的人,以及一个简单的研究技术的人。

TOP

回复 11# GNGW

嗯???自己动手啦
参考6楼链接
根据代码 自己思考流程或画或写(如下面的) 然后观察流程和实际执行结果
就算实际执行结果不一致 也总有自己的理解或见解吧
不知道对不对 是不是这样 就多弄些例子验证并总结就是

代码
  1. setlocal enabledelayedexpansion
  2. @echo ^^!
  3. echo ^^
  4. pause
复制代码
流程
  1. 读取第1行,得到setlocal enabledelayedexpansion
  2. 读取到的不包含% , 不需要预处理(或处理前后一致)
  3. 解析读取到的内容 , 解析后得到命令setlocal和命令参数enabledelayedexpansion
  4. 显示解析到的内容setlocal enabledelayedexpansion(因为命令开头不是@ , 之前也没有关闭回显)
  5. 执行命令setlocal , 执行后开启了变量延迟
  6. 读取第2行,得到@echo ^^!
  7. 读取到的不包含% , 不需要预处理(或处理前后一致)
  8. 解析读取到的内容 , 解析后得到以@开头的命令echo和命令参数^!
  9. 将解析后的内容扔给变量延迟处理(因为开启了变量延迟) , 处理后得到以@开头的命令echo和命令参数!
  10. 执行echo命令 , 显示输出一个!
  11. 继续读取第3行,得到echo ^^
  12. 不需要预处理
  13. 解析读取到的内容 , 解析后得到命令echo和命令参数^
  14. 显示解析到的内容echo ^
  15. 将解析后的内容扔给变量延迟处理 , 处理后得到命令echo和命令参数^(处理前后一致 , 因为内容不包含!)
  16. 执行echo命令 , 显示输出一个^
  17. 继续读取第4行,得到pause
  18. 不需要预处理
  19. 解析读取到的内容 , 得到命令pause
  20. 显示解析到的内容pause
  21. 将解析后的内容扔给变量延迟处理 , 处理后得到命令pause
  22. 执行命令pause , 请按任意键继续. . .
  23. 按任意键后 , 结束
复制代码

TOP

返回列表