具有延迟变量膨胀的 for 循环中的转义"!"



我需要在启用延迟变量扩展的for循环中转义"!"(和其他特殊字符(

我已经尝试过用字符串替换^^手动转义可变循环!在循环变量%%a中,但运气不佳。是不是已经太晚了?如果是这样的话,我怎么能做到这一点呢?

下面是一个简短的函数。这里唯一相关的部分是for循环和echo语句。也就是说,每X行打印一个文件的整行,这些行就是文件路径。它们(有时(包含像"!"这样的字符和其他麻烦的特殊字符。我只是想让echo在这里传递它,而不需要解释它——但它最终删除了我的"!"字符。对于我的使用来说,它们需要准确无误,否则就毫无用处,因为它们必须在以后的使用中与实际文件相关。

setlocal EnableDelayedExpansion
:SplitList
if [%3] == [] goto :SplitListUsage
set inputfile=%~1
set outputfile=%~2
set splitnumber=%~3
set skipLines=0
set skipLines=%~4
if %skipLines% GTR 0 (
set skip=skip=%skipLines%
) else (
set skip=
)
@echo off > %outputfile%
set lineNumber=0
for /f "tokens=* %skip% delims= " %%a in (%inputfile%) do (
set /a modulo="!lineNumber! %% !splitnumber!"
if "!modulo!" equ "0" (
echo %%a >> !outputfile!
)
set /a lineNumber+=1
)
exit /B 0

快速解决方案:

if !modulo! equ 0 (
setlocal DisableDelayedExpansion
(echo %%a)>> "%outputfile%"
endlocal
)


更好的解决方案:

根据您的代码示例,不需要为整个代码启用延迟扩展,
事实上,您应该禁用它,以免干扰可能包含!的文件名或输入字符串,并在必要时启用它:

setlocal DisableDelayedExpansion
REM Rest of the code...
for /f "tokens=* %skip% delims= " %%a in (%inputfile%) do (
set /a "modulo=lineNumber %% splitnumber"
setlocal EnableDelayedExpansion
for %%m in (!modulo!) do (
endlocal
REM %%m is now have the value of modulo
if %%m equ 0 (
(echo %%a)>> "%outputfile%"
)
)
set /a lineNumber+=1
)


旁注:

您的代码中还有一些其他问题,正如您可能已经注意到的,其中一些问题在上述解决方案中得到了纠正。但为了不分散你们对主要问题的注意力,我在这里单独介绍了它们

在向outputfile写入代码时,还有提高代码性能的空间。

这是重写的代码,涵盖了其余部分:

@echo off
setlocal DisableDelayedExpansion
:SplitList
if "%~3"=="" goto :SplitListUsage
set "inputfile=%~1"
set "outputfile=%~2"
set "splitnumber=%~3"
set "skipLines=0"
set /a "skipLines=%~4 + 0" 2>nul
if %skipLines% GTR 0 (
set "skip=skip=%skipLines%"
) else (
set "skip="
)
set "lineNumber=0"
(
for /f "usebackq tokens=* %skip% delims= " %%a in ("%inputfile%") do (
set /a "modulo=lineNumber %% splitnumber"
setlocal EnableDelayedExpansion
for %%m in (!modulo!) do (
endlocal
REM %%m is now have the value of modulo
if %%m equ 0 echo(%%a
)
set /a lineNumber+=1
)
)>"%outputfile%"
  • 您没有使用双qoutes"(例如set inputfile=%~1(来保护变量赋值。如果现在裸露的批处理参数%~1包含空格或特殊字符(如&(,则批处理文件将失败,可能是由于语法错误导致的致命错误,也可能是在执行时数据不正确。推荐的语法是使用set "var=value",它不将引号分配给变量值,但提供针对特殊字符的保护。它还保护赋值不受意外尾随空格的影响
  • %inputfile%可能包含特殊字符或空格,因此在FOR /F的in子句中使用时,应使用双引号对其进行保护。在FOR /F中对文件名进行双引号引用时,还必须使用usebackq参数
  • 对于SET /A,不需要扩展变量值:set /a modulo="!lineNumber! %% !splitnumber!"。变量名可以直接使用,无论是否延迟扩展,它都能正常工作
  • FOR循环中使用(echo %%a) >> "%outputfile%"会带来严重的性能损失,特别是在大量迭代的情况下,因为在每次迭代时,输出文件都会被打开、写入,然后关闭。为了提高性能,整个FOR循环可以重定向一次。任何新数据都将附加到已打开的文件中
  • 奇怪的echo(是为了防止空的变量值,或者当变量值是/?时。如果变量为空,则使用echo %%a可以打印"ECHO is on/off"消息,或者可以打印回显使用帮助
  • 在主要的解决方案中,我使用(echo %%a)>> "%outputfile%"而不是echo %%a >> "%outputfile%"的原因是为了防止输出%%a>>之间的额外空间。现在您知道了使用echo(的原因,很容易理解更安全的替代方案:(echo(%%a)>> "%outputfile%"

最新更新