在Windows批处理文件中如何回显精确字符串?

7

我想要输出一个存储在变量中的字符串,但貌似需要进行大量转义。我尝试使用以下代码:

setlocal EnableDelayedExpansion
@echo off
set "grass=@##&!$^&%**(&)"
echo !grass!

我想要直接输出变量 grass 的值,以便在输出中看到 @##&!$^&%**(&)。应该怎么做?谢谢!

2个回答

16

echo !grass!将始终直接输出当前值,无需进行任何转义。你的问题在于,该值并非你所认为的那个值!问题出现在你尝试设置该值时。

正确的转义序列以设置你的值是:

set "grass=@##&^!$^^&%%**(&)"

现在让我来解释一下。你需要的信息被深埋在《Windows命令解释器(CMD.EXE)如何解析脚本?》这篇文章中,但它有点难以理解。

你有两个问题:

1) 在每次解析该行时,%必须转义为%%。引号的存在或缺失并不重要。延迟扩展状态也不重要。

 set pct=%
 :: pct is undefined

 set pct=%%
 :: pct=%

 call set pct=%%
 :: pct is undefined because the line is parsed twice due to CALL

 call set pct=%%%%
 :: pct=%

2) 在解析器的延迟扩展阶段中,必须将 ! 文本保留字转义为 ^!。如果一行文本在延迟扩展期间包含任何位置的 ! 字符,则必须将 ^ 文本保留字转义为 ^^。但是,对于解析器的特殊字符阶段,^ 也必须被引用或转义为 ^^。这个问题可能会变得更加复杂,因为 CALL 命令会使所有的 ^ 字符都翻倍。(很抱歉,很难描述这个问题,而且解析器非常复杂!)

setlocal disableDelayedExpansion

set test=^^
:: test=^

set "test=^"
:: test=^

call set test=^^
:: test=^
:: 1st pass - ^^ becomes ^
:: CALL doubles ^, so we are back to ^^
:: 2nd pass - ^^ becomes ^

call set "test=^"
:: test=^^ because of CALL doubling. There is nothing that can prevent this.

set "test=^...!"
:: test=^...!
:: ! has no impact on ^ when delayed expansion is disabled

setlocal enableDelayedExpansion

set "test=^"
:: test=^
:: There is no ! on the line, so no need to escape the quoted ^.

set "test=^!"
:: test=!

set test=^^!
:: test=!
:: ! must be escaped, and then the unquoted escape must be escaped

set var=hello
set "test=!var! ^^ ^!"
:: test=hello ^ !
:: quoted ^ literal must be escaped because ! appears in line

set test=!var! ^^^^ ^^!
:: test=hello ^ !
:: The unquoted escape for the ^ literal must itself be escaped
:: The same is true for the ! literal

call set test=!var! ^^^^ ^^!
:: test=hello ^ !
:: Delayed expansion phase occurs in the 1st pass only
:: CALL doubling protects the unquoted ^ literal in the 2nd pass

call set "test=!var! ^^ ^!"
:: test=hello ^^ !
:: Again, there is no way to prevent the doubling of the quoted ^ literal
:: when it is passed through CALL

有需要转义的字符列表吗?例如 *( 等等。 - user1077213
这是一个字符及其转义序列列表的链接:https://www.robvanderwoude.com/escapechars.php - duct_tape_coder

2

正如dbenham所说,这只是一个赋值操作。
你可以像dbenham展示的那样使用转义字符,因为在设置变量值时EnableDelayedExpansion处于活动状态。
因此,你需要转义感叹号,并且由于该行中有一个感叹号,所以插入符号也必须进行转义,引号在这种情况下是无用的。
但是,你也可以在激活EnableDelayedExpansion之前设置变量的值,
然后你就不需要插入符号了。


例如,如果在启用延迟扩展之前设置值,那么@##&!$^&%**(&)的转义形式会是什么样子? - user1077213
2
只要值被引用,那么只需要将%加倍:set "grass=@##&!$^&%%**(&)"。如果没有引号,则需要多个转义符:set grass=@##^&!$^^^&%%**(^&)只要不在括号块内就可以工作。如果括号处于活动状态,则还必须转义右括号)set grass=@##^&!$^^^&%%**(^&^) - dbenham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接