【问题标题】:Percent sign disappears when passed by CALL通过 CALL 时百分号消失
【发布时间】:2013-02-08 14:07:03
【问题描述】:

这个问题最初来自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 内部或外部展开,为什么会有不同的结果?随着回声,我看到百分号刚刚消失SET TmpString="~1"。任何解释都将帮助我改进我进一步的 cmd 技术。谢谢!

【问题讨论】:

    标签: windows cmd escaping call


    【解决方案1】:

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

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

    Microsoft Support website 上有关百分号的一些信息)

    【讨论】:

    • 已达到 5 分钟限制 :-) 我现在阅读了您提到的 Microsoft KB,它说在 echo 处理时,单个百分号将被解释为 NUL 字符。通过试用,我发现当字符串用双引号引起来时,也会回显单个百分号。现在我通过 CALL 解析双引号字符串,行为完全改变。奇怪的。马丁
    【解决方案2】:

    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
    

    【讨论】:

      猜你喜欢
      • 2014-05-04
      • 2016-01-15
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 2014-10-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多