转义“!”在具有延迟变量扩展的for循环中

时间:2019-11-08 23:40:43

标签: batch-file

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

我尝试用字符串替换^^手动转义循环变量!在循环变量%% a中却没有运气。 for读完它们已经为时已晚吗?如果是这样,我该怎么做到呢?

下面是一个简短函数。这里唯一相关的部分是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

1 个答案:

答案 0 :(得分:1)

快速解决方案:

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


更好的解决方案:

根据您的代码示例,无需为整个代码启用延迟扩展,
实际上,您应该禁用它,以免弄乱可能包含{{1的文件名或输入字符串}},并在必要时启用它:

!


注意事项:

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

写入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
  • 您没有用双qoutes @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%" 保护变量分配,例如"。如果现在裸露的批处理参数set inputfile=%~1包含空格或特殊字符(如%~1),则批处理文件将失败,可能是致命的语法错误,或者是执行时数据不正确。推荐的语法是使用&,它不会将引号分配给变量值,但是可以防止特殊字符。它还可以保护分配以防意外尾随空格。
  • set "var=value"可能包含特殊字符或空格,因此在%inputfile%的IN子句中使用时,应通过双引号对其进行保护。在FOR /F中双引号时,还必须使用FOR /F参数。
  • 使用usebackq不需要扩展变量值:SET /A。变量名称可以直接使用,无论延迟扩展与否都可以正确使用。
  • set /a modulo="!lineNumber! %% !splitnumber!"循环中使用(echo %%a) >> "%outputfile%"会带来严重的性能损失,特别是在进行大量迭代时,因为在每次迭代时,输出文件都会被打开,写入然后关闭。提高性能整个FOR循环可以重定向一次。任何新数据都将添加到已打开的文件中。
  • 奇异的FOR用于防止空变量值或变量值为echo(时。如果变量为空,则使用/?可以显示“ ECHO is on / off”消息,或者可以显示回显用法帮助。
  • 在主要解决方案中,我使用echo %%a而不是(echo %%a)>> "%outputfile%"的原因是为了防止在echo %%a >> "%outputfile%"%%a之间输出多余的空间。现在您知道了使用>>的原因,很容易理解更安全的替代方法:echo(