找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 3050|回复: 3

[其他] [分享&讨论]批处理变量赋值时含有双引号及特殊符号如何转义

[复制链接]
发表于 2025-8-1 13:53:26 | 显示全部楼层 |阅读模式
  1. @echo off

  2. echo "假设:双引号不成对(不包括被转义的双引号),则末尾存在隐形双引号
  3. echo "已知:双引号对内的特殊字符(包括^<>&|不包括 %%!)无需转义

  4. echo 1.变量名前无双引号:从左(set 后)到右,双引号(包括隐形双引号,不包括被转义的双引号)双双配对,处于 双引号对 外 需要转义,处于 双引号对 内 不需要转义。
  5. rem 存在一个显形双引号,与末尾的隐形双引号配对,引号对内的 "<" 无需转义
  6. set a="<
  7. cmd /v:on /c echo !a!

  8. rem 对比:多余的“转义”字符,变普通字符
  9. set a="^<
  10. cmd /v:on /c echo !a!

  11. rem 存在一个显形双引号 但是被转义了,失去配对资格(没有双引号对,所有字符都在双引号对之外),需要转义 "<"
  12. set a=^"^<
  13. cmd /v:on /c echo !a!

  14. rem 第一个双引号被转义,失去配对资格,第二个双引号与末尾的隐形双引号配对,无需转义 "<"
  15. set a=^""<
  16. cmd /v:on /c echo !a!

  17. rem 前两个双引号配对,第三个与末尾的隐形双引号配对,第一个 "<" 无需转义,第二个 "<" 需要转义,末尾 "|" 无需转义
  18. set a="<"^<"|
  19. cmd /v:on /c echo !a!


  20. echo=
  21. echo 2.变量名前有双引号:仍按上一条规律,变量值去除了最后一个显形双引号及其后的内容
  22. rem 双引号对内的 "|" 无需转义,双引号对外的 "|" 需要转义
  23. set "a="^|"|"1""""
  24. cmd /v:on /c echo !a!

  25. rem 即使变量值去除了最后一个显形双引号及其后的内容,最后一个双引号后的内容仍需要按规律书写转义
  26. set "a="^|"|"1""^<
  27. cmd /v:on /c echo !a!


  28. echo=
  29. echo 3."^" 处于双引号对内,则其失去转义作用(只是普通字符),此时其后跟随的双引号仍为可以配对的双引号
  30. rem "^" 处于双引号对内,失去转义作用
  31. set "a=^""<"1
  32. cmd /v:on /c echo !a!

  33. rem 第3个双引号被转义,失去配对资格,第4个双引号与隐形双引号配对,第4个双引号之前的 "<" 处于双引号对外,需要转义
  34. set "a=^"1^"^<"<
  35. cmd /v:on /c echo !a!


  36. echo=
  37. echo 4. "^" 处于末尾情况
  38. rem "^" 处于双引号对外,末尾的偶数位数 "^" 被奇数位数 "^" 转义为普通字符。末尾的 "^" 数量为奇数时,最后一个 "^" 未被转义,连接了下一行
  39. set c="1"^^^
  40. 2
  41. cmd /v:on /c echo c=!c!

  42. set d="1"^^^^
  43. cmd /v:on /c echo d=!d!

  44. rem "^" 处于双引号对内(第一个双引号与与隐形的双引号配对),无论多少个 "^" 均被双引号对转义,为普通字符
  45. set e="^^^^^
  46. cmd /v:on /c echo e=!e!

  47. rem 一个复杂例子,"^" 处于双引号对外,连接了下一行,但是变量名前存在双引号,最后一个双引号及其后的内容被去除,且 "^" 仍有转义作用,转义了 "&"
  48. set "f=1"^
  49. &"2
  50. cmd /v:on /c echo f=!f!
  51. pause
复制代码


我试着总结了下。另外1.特殊符号在不同的环境下会有变化;2.其它命令大概也适用。如echo "&、if 跟vbs命令需转义)、for /f in ('echo ^=') 等。请多多指正!
发表于 2025-8-2 05:58:58 | 显示全部楼层
其实就是从左往右 ,与距离最近的双引号配对 ,不在双引号对里或者没有被单个双引号引起来的都要转义
经过解析后 ,set命令及其内容就分离出来了 ,如果变量名开头是双引号就去掉"开头的引号"跟"最后一个引号及其后内容" ,保留剩下的
感觉这样的规则是真的恶心 ,尤其是跟外部程序混在一起时就更加了 ,既要满足这样的规则又要满足外部程序的规则 ,最典型的就是用vbs以管理员身份运行包含特殊字符文件名的bat了

评分

参与人数 1技术 +1 收起 理由
77七 + 1 感谢分享

查看全部评分

发表于 2025-8-2 12:39:03 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-8-2 12:40 编辑

回复 1# 77七

踩着老帖的脚印走过来再加上一些力所能及的实证,可简要理解 cmd 处理字符串中特殊字符的转义机理如下》
奇数个双引号开启特殊字符转义,第偶数个双引号关闭特殊字符转义,如没有第偶数个双引号则至当前行结束自动关闭。看以下示例代码,用转义符^本身是否被保留表示转义被开启或被关闭

  1. @echo off
  2. echo,我^被转义 "我^未被转义" 我^被转义
  3. echo,"我^未被转义" 我^被转义 "我^未被转义"
  4. echo,"我^未被转义 我^未被转义
  5. echo,我^被转义 "我^未被转义
  6. pause&exit/b
复制代码
至于双引号本身在字符串中的转义方法,会根据当前语境有所变化,批处脚本中可用 ^" 或 "" 转义单个双引号,在传递给c/c++/c#系列程序的参数字符串中可用 \" 转义单个双引号,在调用 powershell 代码中的字符串内可用 """ 转义单个双引号,在调用 vbs 代码中的字符串内可用 "" 转义单个双引号,...等等。其余特殊符号的一些常见转义方法可参考旧帖 http://www.bathome.net/thread-66857-1-1.html

评分

参与人数 1技术 +1 收起 理由
77七 + 1 感谢分享,这种说法更方便理解

查看全部评分

发表于 2025-8-2 16:22:28 | 显示全部楼层
其实是有两步:
首先是cmd解析命令行,处理特殊字符和扩展变量,逐字符解析,其中有以遇到引号为条件开或关转义功能。
然后内部或外部命令根据其自己规则处理参数,set的规则就是——如果参数以引号开头,就去掉开头的引号和后续空白字符,并找到最后一个引号,去掉这个引号及其后字符。
  1. 即使变量值去除了最后一个显形双引号及其后的内容,最后一个双引号后的内容仍需要按规律书写转义
  2. "^" 处于双引号对外,连接了下一行,但是变量名前存在双引号,最后一个双引号及其后的内容被去除,且 "^" 仍有转义作用
复制代码
1楼这两句似乎弄错了顺序,不是先去除再转义,而是先cmd转义再set去除。所以最后一个双引号后的内容才也需要符合cmd解析的规则。

评分

参与人数 1技术 +1 收起 理由
77七 + 1 感谢分享、指正

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 06:07 , Processed in 0.028133 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表