【问题标题】:Batch - Replace line in text file using for loop including blank lines批处理 - 使用 for 循环替换文本文件中的行,包括空行
【发布时间】:2019-08-26 17:25:52
【问题描述】:

我找到了 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 行的原始内容。

【问题讨论】:

    标签: loops batch-file for-loop replace


    【解决方案1】:

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

    不管怎样,首先我想展示一下适应后的工作代码:

    @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" 命令行实际上出现在禁用延迟扩展的代码部分中,这是为了避免@987654332 出现问题所必需的@出现在文件中;

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

    • 我在顶部添加了@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;这意味着该文件包含少于 231 行;
    • if 子句更改为if !num! equ !linenumber!,由于equ 因为两个表达式都是整数,所以它执行数字比较;所以这不再取决于行号的位数;在这里我也可以使用%linenumber%,因为变量在代码块中没有更改,但我决定使用!linenumber! 来解决该变量初始化错误的情况(特别是当它为空白或包含特殊字符时错别字);

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

    【讨论】:

      【解决方案2】:

      你可以这样尝试:

      @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"
      

      【讨论】:

      • 我得到“Echo is off”代替空行。
      • 在我编辑我的答案之前你一定已经尝试过了,要添加=,请再试一次!
      • 这是Echo之后推荐使用的字符之一,以防止它输出Echo的状态。测试发现 (/= 比大多数人使用的通常的 . 字符更好。我更喜欢使用 (=,在这种情况下选择了后者,因为我认为它在短括号内看起来更好。
      • 我注意到如果我使用 !taglinelinks! 而不是 %taglinelinks% 我会丢失一行中的第一个 !
      • 我没有设置或使用延迟扩展,因为它不是必需的。只有在代码块中更改变量的值时才需要延迟扩展,没有变量被更改,因为来自For 块的元变量正在做这项工作。 %taglinelinks% 是在 For 块之前设置的,并且在其中没有更改,那么为什么您会觉得需要使用变量的延迟扩展形式?如果您希望使用延迟扩展,并防止任何可能以一个或多个 : 字符开头的行丢失它们,请选择使用来自@aschipfl 的答案。
      猜你喜欢
      • 2013-10-07
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      相关资源
      最近更新 更多