我需要在启用延迟变量扩展的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%"