2

这个问题最初来自Escape percent sign in given variables。我不想打乱那边的好答案。但是我的问题发生了一点变化......

假设有一个用双引号括起来的给定字符串变量,其中可能包含一个或多个百分号。无法永久切换到启用的延迟扩展(其他代码已经可用)。调用包含字符串变量作为参数的函数是必要的。这是我到目前为止确定的:

@echo off & setlocal ENABLEEXTENSIONS
SET AlbumArtist=%1
CALL :EscapePoisonChars %AlbumArtist% AlbumArtist_VDN
echo %AlbumArtist_VDN%

CALL :EscapePoisonChars %%AlbumArtist%% AlbumArtist_VDN
echo %AlbumArtist_VDN%
endlocal &GOTO:EOF

:EscapePoisonChars
@echo off & setlocal ENABLEEXTENSIONS
SET TmpString="%~1"
SET TmpString=%TmpString:&=^^^&%
SET TmpString=%TmpString:(=^^^(%
SET TmpString=%TmpString:)=^^^)%
endlocal&SET %2=%TmpString:~1,-1%&GOTO :EOF

我知道这可能不是一个“干净的解决方案”。但是我想了解为什么当CALL :EscapePoisonChars %AlbumArtist% AlbumArtist_VDN百分号调用例程时会消失。%%AlbumArtist%%当用双百分号括起来的字符串变量调用时,它会给出想要的输出:

D:\Batch>PercentTwins.bat "100% Rock & Roll"
100 Rock & Roll
100% Rock & Roll

D:\Batch>

如果 %AlbumArtist% 在函数内部或外部扩展,为什么会有不同的结果:EscapePoisonChars?随着回声,我看到百分号消失了SET TmpString="~1"。任何解释都将帮助我改进我进一步的 cmd 技术。谢谢!

4

2 回答 2

1

如果我错了,任何人都可以纠正我,但我认为当一个命令中的单个百分号传递给另一个命令时,它们会消失。如果它只是在同一个命令中使用,它通常不会消失。

(可能有一种更“正确”的说法,或者这个想法可能完全错误)

(微软支持网站上有关百分号的一些信息)

于 2013-02-08T16:18:07.017 回答
0

call命令%第二次启动解析阶段(参考已接受的问题帖子Windows 命令解释器(CMD.EXE)如何解析脚本?);这让%迹象消失。您可以提前将符号加倍%,但您需要为此启用延迟扩展,如下所示:

@echo off & setlocal ENABLEEXTENSIONS EnableDelayedExpansion
SET AlbumArtist=%1
set AlbumArtist=!AlbumArtist:%%=%%%%!
CALL :EscapePoisonChars %AlbumArtist% AlbumArtist_VDN
echo %AlbumArtist_VDN%
endlocal &GOTO:EOF

在您的第二个子例程调用中,两个解析阶段看不到%原始字符串的符号;第一阶段从字面上扩展%%AlbumArtist%%%AlbumArtist%,第二阶段将其扩展为100% Rock & Roll.

但是:
不需要所有这些,当您坚持唯一安全的set语法并确保始终正确引用字符串时,您根本不需要子例程:

set "AlbumArtist=%~1"

%1将返回给定的字符串;%~1删除潜在的周围引号。将整个赋值表达式括在引号内使得语法对有毒字符具有鲁棒性,因为它考虑""作为分配字符串本身的一部分。

使用/返回字符串时(echo如此处的示例所示),您需要再次将字符串括在引号内以保持安全,以防您使用正常(立即)%扩展:

set "AlbumArtist=%~1"
echo "%AlbumArtist%"

或者,即使没有引号,延迟扩展也可以使读取变量安全:

set "AlbumArtist=%~1"
setlocal EnableDelayedExpansion
echo !AlbumArtist!
endlocal
于 2016-09-26T18:26:36.007 回答