繁体   English   中英

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

[英]escaping “!” in a for-loop with delayed variable expansion

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

我已经在循环变量中手动尝试了 escaping 使用字符串替换 ^^ 的循环变量。 %%a 但一点运气都没有? 在 for 阅读它们之后是否已经太晚了,如果是这样? 我怎么能做到这一点?

下面是一个简短的 function。 这里唯一相关的部分是 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时,代码的性能还有提升的空间。

这是覆盖 rest 的重写代码:

@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%可能包含特殊字符或空格,因此在FOR /F的 IN 子句中使用时应通过双引号对其进行保护。 FOR /F中对文件名进行双引号时,还必须使用usebackq参数。
  • 使用SET /A无需扩展变量值: set /a modulo="!lineNumber! %% !splitnumber!" . 变量名可以直接使用,不管有没有延迟扩展,它都能正常工作。
  • FOR循环中使用(echo %%a) >> "%outputfile%"会导致严重的性能损失,特别是在进行大量迭代时,因为在每次迭代中 output 文件将被打开、写入然后关闭。 提高性能 整个FOR循环可以重定向一次。 任何新数据都将附加到已打开的文件中。
  • 奇怪的echo(是为了防止空变量值,或者当变量值为/?时。如果变量为空,使用echo %%a可能会打印 `ECHO is on/off' 消息,或者可能会打印回声用法帮助。
  • 在主要解决方案中,我使用(echo %%a)>> "%outputfile%"而不是echo %%a >> "%outputfile%"的原因是为了防止输出%%a>> 现在您知道了使用echo(的原因,很容易理解更安全的选择: (echo(%%a)>> "%outputfile%"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM