batch-file - 转义“!” 在具有延迟变量扩展的 for 循环中
问题描述
我需要逃脱“!” (和其他特殊字符)在启用延迟变量扩展的 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
解决方案
快速解决方案:
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%"
- 您没有使用双引号来保护变量赋值,
"
例如set inputfile=%~1
. 如果现在裸批处理参数%~1
包含空格或特殊字符,例如&
您的批处理文件失败,则可能因语法错误而致命,或者在执行时数据不正确。推荐的语法是使用set "var=value"
不将引号分配给变量值但提供对特殊字符的保护。它还保护分配免受意外尾随空格的影响。 - 可能包含特殊字符或空格,因此在's IN 子句
%inputfile%
中使用时应通过双引号对其进行保护。双引号时,参数FOR /F
中的文件名也必须使用。FOR /F
usebackq
SET /A
无需扩展变量值set /a modulo="!lineNumber! %% !splitnumber!"
:. 变量名可以直接使用,不管有没有延迟扩展,它都能正常工作。(echo %%a) >> "%outputfile%"
在循环内使用FOR
会导致严重的性能损失,特别是在大量迭代时,因为在每次迭代中,输出文件都会被打开、写入然后关闭。提高性能整个FOR
循环可以重定向一次。任何新数据都将附加到已打开的文件中。- 奇怪的外观
echo(
是为了防止空变量值,或者当变量值为/?
. 如果变量为空,使用echo %%a
可能会打印“ECHO 开启/关闭”消息,或者可能会打印回显使用帮助。 - 在主要解决方案中,我使用
(echo %%a)>> "%outputfile%"
代替的原因echo %%a >> "%outputfile%"
是为了防止输出 and 之间的额外%%a
空间>>
。现在您知道了使用的原因echo(
,很容易理解更安全的替代方案:(echo(%%a)>> "%outputfile%"
推荐阅读
- javascript - 使用 Alpine JS 将鼠标悬停在下拉菜单上
- python - 为节点分配颜色时出现 KeyError
- reactjs - 带有 InnerBlocks 模板的 WordPress 块转换
- python - 不可读的智能感知工具提示
- python - 如何在 bert 模型上添加 Bi-LSTM 层?
- reactjs - 当我在反应中更改范围滑块时,为什么整个页面会重新渲染?
- curity - 由于许可问题,无法在 Curity 中创建数据源
- polymorphism - OCaml 中的多态类型
- python - 是否有可能将熊猫数据框的每一行转换为预定义的文本文件?
- javascript - 我什么时候应该使用 bignumber 库?