批处理-使用for循环替换文本文件中的行,包括空行

时间:2019-04-04 20:51:05

标签: loops batch-file for-loop replace

我找到了杰布(Jeb)的答案,可以通过在每行的开头添加数字:将文件复制到另一个包含空行的文件

(
set taglinelinks=one two three
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ overview.md"`) do (
    set "var=%%a"
    if "%var:~0,2%" == "5:" (echo %taglinelinks%)
    SETLOCAL EnableDelayedExpansion
    set "var=!var:*:=!"
    echo(!var!
)
) > new.txt

我在顶部添加了用于测试的变量,并添加了“ if”行。没有“ if”行,它可以正常工作,但是我看不到该行有任何问题。我正在检查行数是否为5,如果是,则将变量回显到文件,然后继续。我应该在if语句中使用else命令,但是现在我无法确定要在其中放置什么以防止其余代码跳过第5行的原始内容。

2 个答案:

答案 0 :(得分:2)

在此答案中,我坚持我们的原始代码,并专注于缺陷。基本上,我喜欢这种方法(当然,错误已得到纠正),因为它甚至可以正确处理以冒号:开头的行,并且文本中出现!也不存在任何问题文件,因为切换了延迟扩展。

无论如何,首先,我想显示经过修改的有效代码:

@echo off
setlocal DisableDelayedExpansion
set "taglinelinks=one two three"
> "new.txt" (
    for /F "delims=" %%a in ('findstr /N "^" "overview.md"') do (
        set "var=%%a"
        setlocal EnableDelayedExpansion
        if "!var:~,2!" == "5:" (
            echo(!taglinelinks!
        ) else (
            echo(!var:*:=!
        )
        endlocal
    )
)
endlocal

这就是我所纠正的:

  • if子句必须处于启用了延迟扩展的块中,因此我将其向下移动了一行,并将%更改为!;
  • 我实现了else子句,以使其包含for /F循环主体中的其余代码部分
  • 我添加了一个丢失的endlocal,因此您无法遇到setlocal的嵌套限制,并且set "var=%%a"命令行实际上出现在禁用了延迟扩展的代码部分中,这对于不会引起文件中出现!的麻烦;

以下是一些细微的外观变化:

  • 为了避免将命令回波写入@echo off,我在顶部添加了new.txt
  • 我将最初的setlocal命令移到顶部以首先禁用延迟扩展,因此!甚至可以安全地用于重定向的文件名和第一个set命令中行(因为我们可能不知道延迟扩展是先禁用还是启用);
  • 我也使用引号set来分配变量taglinelinks以使其安全;然后我将这行代码移到了重定向块之外,只是变得更加明显;
  • 尽管它不会打扰,但usebackq选项不是必需的,因此我将其删除并使用了单引号''(但这里只是个问题);
  • 带引号的findstr命令行显得有些奇怪,尤其是转义的插入符号^^,因此我更改了引号,以便对搜索字符串以及文件路径进行引号,因此不会进行此类转义不再需要,文件名甚至可以包含空格或其他特殊字符;
  • 回显taglinelinks值的行不在启用延迟扩展的块中;这允许变量甚至包含特殊字符;
  • 第二个赋值set "var=!var:*:=!"并不是必须的,因此我将其删除并立即回显了被截断的字符串;
  • 我也针对if / else块修改了代码缩进,以提高可读性;
  • 我将重定向> "new.txt"移动到了外部括号块的前面,以使其更加可见(但这在这里只是个问题),并且在文件名两边加上了双引号,因此它甚至可能包含空格或其他特殊字符;
  • 我添加了另一个属于初始endlocal的显式setlocal命令;

我在脚本中仍然不喜欢一件事,即不灵活的方式来标识当前行的编号,因为它当前仅适用于小于10的编号,而无需对代码进行一点改动。

这是一种灵活指定要替换的行号的方法:

@echo off
setlocal DisableDelayedExpansion
set "taglinelinks=one two three"
set "linenumber=5"
> "new.txt" (
    for /F "delims=" %%a in ('findstr /N "^" "overview.md"') do (
        set "var=%%a"
        setlocal EnableDelayedExpansion
        set /A "num=var"
        if !num! equ !linenumber! (
            echo(!taglinelinks!
        ) else (
            echo(!var:*:=!
        )
        endlocal
    )
)
endlocal

这就是我所做的:

  • 首先,我以行号linenumber定义了一个变量(常量)5;认为linenumber不能包含前导零,以便以后不将其解释为八进制整数(由if表示);
  • 在循环中我放置了set /A "num=var",该循环利用了set /A的隐式变量扩展,这意味着该行字符串从左到右扫描到第一个非数字字符 1 ,然后将此字符串转换为整数,最后分配给num;这意味着该文件包含少于2 31 行;
  • if子句更改为if !num! equ !linenumber!,由于两个表达式都是整数,因此由于equ而执行数字比较。因此,这不再取决于行号的位数;在这里我也可以使用%linenumber%,因为代码块中的变量没有更改,但是我决定使用!linenumber!来覆盖该变量初始化错误的情况(尤其是当它为空或包含拼写错误引起的特殊字符);

1)实际上忽略前导的 SPACE TAB 。接下来可能会出现单个+-符号。然后使用直到下一个非数字数字的所有内容将字符串转换为带符号的32位整数。如果结果不能如此表示,它将被强制。

答案 1 :(得分:1)

您可以这样尝试:

@Echo Off
Set "taglinelinks=one two three"
(   For /F "Tokens=1*Delims=:" %%A in ('Findstr /N "^" "overview.md"')Do (
        If %%A NEq 5 (Echo=%%B)Else Echo %taglinelinks%
    )
)>"new.txt"