如何在cmd脚本中转义感叹号!?

83

当我在cmd脚本中设置了 setlocal ENABLEDELAYEDEXPANSION 后,有没有办法转义一个想要作为命令参数使用的感叹号(!)?

@echo off
setlocal ENABLEDELAYEDEXPANSION
echo I want to go out with a bang!
echo I still want to go out with a bang^!
4个回答

97

这就是我找到的(^^)

@echo off
setlocal ENABLEDELAYEDEXPANSION
echo I want to go out with a bang^^!

3
顺便问一下,如果你必须替换变量中的感叹号,你会怎么做? - crosenblum
2
@crosenblum 我建议您将此作为自己的问题提出。这样它将对所有SO成员可见,并且很可能会得到答复。 - FrVaBe
1
如果感叹号在您设置/使用或传递给调用标签的变量中,则此解决方案(以及其他解决方案)将无效,这种情况下我认为您会很遗憾。 - Abel

76

对于 FrVaBe回答,我有一个额外的备注。

通常情况下,^^! 是有效的,但是在引号中,你只需要使用 ^!

echo I want to go out with a bang^^!
echo He said "Bang^!"

这是批处理解析器的转义机制导致的结果。

首先,解析器会解析一行,并且插入符号(^)会转义下一个字符,对于&|<>()"<linefeed>,在引号外面有影响,但在引号内部,所有字符都是“正常”的,插入符本身没有效果。

使用延迟扩展功能后,会跟随额外的解析步骤,这时插入符也是下一个字符的转义字符,但只会影响^,并且在此解析步骤中忽略了引号。只有当该行中至少有一个!时,才会执行此额外的解析步骤。

setlocal DisableDelayedExpansion
echo DisableDelayedExpansion
echo one caret^^
echo one caret^^  bang! "boom^!"

echo(
setlocal EnableDelayedExpansion
echo EnableDelayedExpansion
echo one caret^^
echo none caret^^  bang^^! "boom^!"

---- 输出 ------

DisableDelayedExpansion
one caret^
one caret^  bang! "boom^!"

EnableDelayedExpansion
one caret^
none caret  bang! "boom!"


编辑

下面是一个稍微修改过的示例,更好地说明了取决于上下文所需的各种转义排列组合。唯一需要不寻常转义的情况是最后一个示例,当启用延迟扩展并且行中存在至少一个!时。

@echo off
setlocal DisableDelayedExpansion
echo DisableDelayedExpansion
echo caret^^       "caret^"
echo caret^^ bang! "caret^ bang!"

echo(
setlocal EnableDelayedExpansion
echo EnableDelayedExpansion
echo caret^^       "caret^"
echo caret^^^^ bang^^! "caret^^ bang^!"

-- 输出 --

DisableDelayedExpansion
caret^       "caret^"
caret^ bang! "caret^ bang!"

EnableDelayedExpansion
caret^       "caret^"
caret^ bang! "caret^ bang!"

18
要在启用延迟扩展的批处理中使用感叹号,您必须首先将感叹号添加到一个已禁用延迟扩展的变量中。请参考以下示例,其中包含了DISABLEDELAYEDEXPANSIONENABLEDELAYEDEXPANSION状态。
@echo off
setlocal DISABLEDELAYEDEXPANSION
set DB_password=encrypt!Pws
echo %DB_password%
SETLOCAL ENABLEDELAYEDEXPANSION
echo !DB_password!

最佳答案!这解决了需要DELAYEDEXPANSION的脚本中的使用问题。 - JasonXA
这很反常。需求中根本没有考虑内存问题,但我却经常使用它而没有任何不良影响。除非你真的能做出贡献,否则请自己保持安静。 - JasonXA
我实际上像你一样编写了我的代码,然后想到“这不可能行得通,因为启用延迟扩展时会丢失!”,在整个互联网上搜索解决方案,最终来到这里,阅读了最后一个答案,并发现我的代码一直可以工作,只是我没有意识到它只被替换了一次...非常感谢^!^!;D - timlg07

6

谢谢。补充一下,如果脚本中的一个变量包含一个“!”,那么以下方法会按原样渲染该值:

@echo off
SETLOCAL EnableDelayedExpansion
set /P omg=输入包含感叹号的值:
echo 传统: %omg%
echo 替代方式: !omg!
pause

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