[英]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.