当字符串在批处理文件中包含 %(百分号)时使用带有变量扩展的调用
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
) 和立即变量扩展 (%%
) 可以防止脚本 运行 陷入所有这些问题。
当扩展变量在字符串中包含“%”时,我在使用调用传递由变量表示的值时遇到问题。我知道,在个人基础上,我只会使用转义字符(大概是 %%),但这些变量来自其他人根据他们的想法创建和更改的文件夹名称。
我尝试了多种不同的修复和诊断尝试(如下所示)。
代码示例:(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
) 和立即变量扩展 (%%
) 可以防止脚本 运行 陷入所有这些问题。