此问题最初来自Escape percent signs 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
之内或之外展开,为什么会有不同的结果?有了echo,我看到百分号随SET TmpString="~1"
消失。任何解释都将帮助我改进我的进一步cmd技术。谢谢!
答案 0 :(得分:1)
如果我错了,任何人都会纠正我,但我认为当一个命令中的单个百分号符号传递给另一个命令时,它们将消失。如果它只是在同一个命令中使用,它通常不会消失。
(可能有更'正确'的说法,或者这个想法可能完全错了)
(有关Microsoft Support website处百分号的一些信息)
答案 1 :(得分:0)
call
命令第二次启动%
解析阶段(引用问题帖How does the Windows Command Interpreter (CMD.EXE) parse scripts?的已接受答案);这让%
标志消失了。您可以提前将%
符号加倍,但您需要为此启用delayed expansion,如下所示:
@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
删除了潜在的引号。将整个赋值表达式括在引号中会使 not 的语法对于有毒字符具有鲁棒性,将""
视为已分配字符串本身的一部分。
当使用/返回字符串时(通过此处示例中的echo
),您需要再次将字符串括在引号内以保持安全,以防您使用正常(立即)%
扩展:
set "AlbumArtist=%~1"
echo "%AlbumArtist%"
或者,延迟扩展使读取变量即使没有引号也是安全的:
set "AlbumArtist=%~1"
setlocal EnableDelayedExpansion
echo !AlbumArtist!
endlocal