批处理文件:防止for / f循环中的文字解释

时间:2013-10-30 13:23:00

标签: list batch-file for-loop escaping batch-processing

目前,我有一个循环,它贯穿项目列表并将它们复制到目录(存档)。但是,列表中的一个项目(路径名中有一个全局变量)正在被“逐字地”解释(作为文本而不是代码)。 我知道通常你可以通过(^^)来逃避它,把它解释为代码而不是文本,但显然我在这里做错了,因为它不起作用......

my.list中的项目(包含其中的转义)存在问题:

location\foo^^%date:~0,3%*.zip

我正在使用的代码是......

for /f "delims=" %%a in (my.list) do (
    echo "%%a"
)

Echo的

"location\foo^^%date:~0,3%*.zip"

而不是

location\fooMON*.zip

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

你很困惑何时需要逃离一个角色。

某些字符具有特殊含义(您描述的“代码”)。通常情况下,您可以转义角色,使其被解释为文字(文本)而不是“代码”。

在Windows CMD.EXE中转义字符的最常用方法是在其前面添加一个^字符。有时一个字符串被解析两次,这可能需要^^^的转义序列,(或者在启用延迟扩展时处理^^时可能需要!)。更多轮解析需要更多^个字符。它很快就会变得混乱,需要练习才能掌握它。

但是你的情况完全不同 - 它无法通过转义来解决。你的FOR变量中有“代码”,你希望它被解释为这样。但相反,它被解释为文本。为了理解原因,您必须了解批处理解析的各个阶段发生的顺序。你可以参考How does the Windows Command Interpreter (CMD.EXE) parse scripts?,但它是非常先进的东西,需要时间来消化。

这是一个粗略的概要,显示何时发生各种类型的扩展。 (注意 - 这些步骤编号与链接答案的阶段编号不完全匹配)

1)参数扩展 - %1
2)正常变量扩展 - %var%
3)FOR变量扩展 - %%A
4)延迟变量扩展 - !var!
5)CALL扩展 - 重复步骤1)和2)如果涉及CALL

您希望%date:~0,3%字符串进行正常(百分比)扩展。你的FOR循环逐字读取文本行,没有任何扩展。当扩展%%a FOR变量时,解析器第一次看到您的“代码”在步骤3)。你可以看到这已经太晚了 %date:~0,3%扩展您想要的方式。

您有两种选择来解决您的问题。但请注意 - 这些解决方案中的每一个都可能会增加可能需要解决的新问题。

我假设^^是你试图强制扩展嵌入式“代码”的天真尝试。 应从列表文件中删除^^

选项1:使用CALL

添加一轮额外的正常扩展
for /f "delims=" %%a in (my.list) do call echo "%%a"

但是现在你有一个潜在的问题,你的列表中可能有一个%字面值想要展开。批处理脚本中的百分比无法使用^进行转义。相反,你通过将它加倍为%%来逃避百分比。因此,如果列表中包含百分比文字,则必须加倍。

请注意,随问题发布的原始代码要复杂得多。它包括一个引用%%a的IF语句。你不能调用IF或FOR命令。解决方案是调用子程序,传递值,并在子程序中包含复杂逻辑。

for /f "delims=" %%a in (my.list) do call :processValue "%%a" >>Logs\xfer.log
exit /b

:processValue
echo Attempting to archive %1...
if exist "c:\%~1" (
  echo f | xcopy "c:\%%a" "c:\Lucas\archive\%~1" /E /C /H /R /Y
  if %errorlevel%==0 (
    echo ...%1 added to archive for transfer
    echo.
  ) else (
    echo ERROR: %1 not added to archive
    echo.
  )
) else (
  echo ERROR: %1 Not found on client computer
  echo.
)

选项2:使用延迟展开

启用延迟展开,并将列表更改为使用!date:~0,3!而不是%date:~0,3%。在FOR变量扩展之后发生延迟扩展,因此它将被正确扩展。

setlocal enableDelayedExpansion
for /f "delims=" %%a in (my.list) do echo "%%a"

但是现在你有一个潜在的问题,你的列表中可能有一个!字面值想要展开。您可以通过将!转义为^!来保留{{1}}文字。