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

时间:2016-03-30 18:45:32

标签: batch-file cmd escaping 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

结果部分:

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 包含"%"它作为自己的值传递,而不是与传递给调用的其他变量连接。

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

1 个答案:

答案 0 :(得分:0)

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

以下是修改后的代码:

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 /?)。

当然,您只需在代码中用%替换每个%%符号,例如call :findMostRecentFile "!fullFolderPath:%%=%%%%!" "%~3"(每个%加倍,因为%%制作一个文字%)。但是有更多字符可能会导致麻烦,例如感叹号!,因为您已启用延迟变量扩展(因此与%相同的问题适用)或^,{{ 1}},&(,也可能出现在路径中,还有)<>|。通过使用延迟扩展(")来避免参数扩展(%1)以及立即变量扩展(%%)可以防止脚本遇到所有这些问题。