当字符串在批处理文件中包含 %(百分号)时使用带有变量扩展的调用

Using call with variable expansion when string contains % (percent sign) in a batchfile

当扩展变量在字符串中包含“%”时,我在使用调用传递由变量表示的值时遇到问题。我知道,在个人基础上,我只会使用转义字符(大概是 %%),但这些变量来自其他人根据他们的想法创建和更改的文件夹名称。

我尝试了多种不同的修复和诊断尝试(如下所示)。

代码示例:(setlocal EnableDelayedExpansion)

:findMostRecentFiles
        REM call :findMostRecentFiles %productFile% %pathPrefix% %resultFile%
        break>%~3
        For /f "tokens=* delims=" %%g In (%~1) Do (
            set fullFolderPath=%~2\%%g\
            Echo !fullFolderPath!
            Echo !fullFolderPath!>>%~3
            Echo Calling findMostRecentFile:
            call :findMostRecentFile "!fullFolderPath!" "%~3"
        )
    goto :eof

:findMostRecentFile
    :: REM call :findMostRecentFile "!fullFolderPath!" %~3 
    :: Echo %~1
    Echo Checking FullFolderPath (no quotes): %~1
    Echo Checking FullFolderPath (quotes): "%~1"
    Echo Checking resultFile: %~2
    Echo About to push: "%~1"
    Pushd "%~1"
    cd

    popd
goto :eof

部分结果:

set fullFolderPath=S:\QA\BA 25% TMAH\
 Echo !fullFolderPath!
 Echo !fullFolderPath! 1>>C:\Users\M2\Desktop\ProductList_Recent.txt
 Echo Calling findMostRecentFile:
 call :findMostRecentFile "!fullFolderPath!" "C:\Users\M2\Desktop\ProductList_Recent.txt"

)
S:\QA\BA 25% TMAH\
Calling findMostRecentFile:

S:\QA>Echo Checking FullFolderPath (no quotes): S:\QA\BA 25\Users\M2\Desktop\Produc
tList_Recent.txt
Checking FullFolderPath (no quotes): S:\QA\BA 25\Users\M2\Desktop\ProductList_Recent.txt

S:\QA>Echo Checking FullFolderPath (quotes): "S:\QA\BA 25\Users\M2\Desktop\ProductL
ist_Recent.txt"
Checking FullFolderPath (quotes): "S:\QA\BA 25\Users\M2\Desktop\ProductList_Recent.
txt"

S:\QA>Echo Checking resultFile:
Checking resultFile:

S:\QA>Echo About to push: "S:\QA\BA 25\Users\M2\Desktop\ProductList_Recent.tx
t"
About to push: "S:\QA\BA 25\Users\M2\Desktop\ProductList_Recent.txt"

S:\QA>Pushd "S:\QA\BA 25\Users\M2\Desktop\ProductList_Recent.txt"
The system cannot find the path specified.

它以一种我没有预料到的方式处理扩展变量(虽然显然是我写的正确行为)而且我不知道如何做到这一点,所以当 fullFolderPath 包含一个“%”,它作为自己的值传递,而不是将它与传递给 call 的其他变量连接起来。

任何帮助或解释都会很棒!

一种可能的解决方法是将变量名而不是值传递给子例程,并在那里应用延迟扩展。

修改后的代码如下:

setlocal EnableDelayedExpansion

:findMostRecentFiles
        REM call :findMostRecentFiles %productFile% %pathPrefix% %resultFile%
        break>%~3
        For /f "tokens=* delims=" %%g In (%~1) Do (
            set fullFolderPath=%~2\%%g\
            Echo !fullFolderPath!
            Echo !fullFolderPath!>>%~3
            Echo Calling findMostRecentFile:
            call :findMostRecentFile fullFolderPath "%~3"
        )
    goto :eof

:findMostRecentFile
    :: REM call :findMostRecentFile fullFolderPath %~3 
    :: Echo !%~1!
    Echo Checking FullFolderPath (no quotes): !%~1!
    Echo Checking FullFolderPath (quotes): "!%~1!"
    Echo Checking resultFile: %~2
    Echo About to push: "!%~1!"
    Pushd "!%~1!"
    cd

    popd
goto :eof

您的代码中的问题在于,子例程参数扩展在命令解释器中发生得相当早,甚至在立即 (%) 变量扩展之前。如果参数中出现单个 % 字符,它就会消失。如果有两个 % 字符,则中间的所有内容都被视为变量名;如果实际上有一个具有该名称的变量,则将其扩展为它的值;如果不是,则删除整个表达式,包括周围的 % 符号。当冒号 and/or 等号出现在百分号之间时,情况更糟,因为这表示子字符串替换语法(有关详细信息,请参见 set /?)。

当然你可以简单地用代码中的 %% 替换每个 % 符号,比如 call :findMostRecentFile "!fullFolderPath:%%=%%%%!" "%~3" (每个 % 加倍为 %% make一个文字 %)。但是还有更多的字符可能会引起麻烦,例如感叹号 !,因为您启用了延迟变量扩展(因此适用于 % 的相同问题),或 ^&(),它们也可以出现在路径中,还有 <>|"。通过使用延迟扩展 (!!) 避免参数扩展 (%1) 和立即变量扩展 (%%) 可以防止脚本 运行 陷入所有这些问题。