【问题标题】:How to search and replace multiple lines with multiple lines如何用多行搜索和替换多行
【发布时间】:2018-05-16 15:55:28
【问题描述】:

我查看了有关搜索和替换的其他答案,但我就是无法理解这些模式。

如何更改文件的这一部分(行号 153 ... 156)

        let view = string.utf8
        offset.pointee += string.substring(to: range.lowerBound).utf8.count
        length.pointee = Int32(view.distance(from:range.lowerBound.samePosition(in: view), to:range.upperBound.samePosition(in: view)))
        return token

并用下面的行替换它?

        let view:String.UTF8View = string.utf8

        if let from = range.lowerBound.samePosition(in: view),
           let to = range.upperBound.samePosition(in: view) {
            offset.pointee += Int32(string[string.startIndex..<range.lowerBound].utf8.count)
            length.pointee = Int32(view.distance(from: from, to: to))
            return token
        } else {
            return nil
        }

【问题讨论】:

  • 数字 153-156 是输入文件的一部分吗?还是您只是在这里展示它们以进行说明?
  • 只是为了说明而展示它们
  • 您是否需要严格替换第 153..156 行或您显示的代码(可能在也可能不在这些行上)?
  • 将 153-156 中的内容替换为代码的第二个 sn-p,这将占用超过 3 行。

标签: bash perl awk sed grep


【解决方案1】:

sed 可能是最好的工具,

假设您的替换文本在文件 replace.txt 中

$ sed '153,156{153{r replace.txt
                  }; d}' file

可能只适用于 GNU sed

【讨论】:

    【解决方案2】:

    如果您没有 GNU-sed 来获取 @karafka 的答案,并且只想在确切的行号处更改行,您也可以使用 ed

    ed -s file <<'EOF'
    153,156c
            let view:String.UTF8View = string.utf8
    
            if let from = range.lowerBound.samePosition(in: view),
               let to = range.upperBound.samePosition(in: view) {
                offset.pointee += Int32(string[string.startIndex..<range.lowerBound].utf8.count)
                length.pointee = Int32(view.distance(from: from, to: to))
                return token
            } else {
                return nil
            }
    .
    w
    q
    EOF
    

    【讨论】:

      【解决方案3】:

      这是Tie::File module 应用程序的一个很好的案例,它将数组映射到文本文件的行,以便您对数组所做的任何更改都会反映在磁盘文件中。它是一个核心模块,因此您不需要安装它。

      在这里,tie 调用将数组 @file 映射到您的文本文件,并且 splice 将四行文本替换为从DATA 读取的替换内容。 然后untie 更新并关闭文件。

      请注意,您必须将myfile.txt 更改为输入文件的真实路径。

      use strict;
      use warnings 'all';
      
      use Tie::File;
      
      tie my @file, 'Tie::File', 'myfile.txt' or die $!;
      
      splice @file, 152, 4, <DATA>;
      
      untie @file;
      
      
      
      __DATA__
              let view:String.UTF8View = string.utf8
      
              if let from = range.lowerBound.samePosition(in: view),
                 let to = range.upperBound.samePosition(in: view) {
                  offset.pointee += Int32(string[string.startIndex..<range.lowerBound].utf8.count)
                  length.pointee = Int32(view.distance(from: from, to: to))
                  return token
              } else {
                  return nil
              }
      

      【讨论】:

        【解决方案4】:

        一个 Perl 单行代码,在 file 中更改行 153..156,内容为 repl.file,就地

        perl -i -wpe'
            if   (153..155) { s/.*\n// }
            elsif ($.==156) { local $/; open $fh, "repl.file"; $_ = <$fh> };    
        ' file
        

        (或$_ = path($file_name)-&gt;slurpPath::Tiny。)

        这直接转化为脚本,可以通过写出带有更改的新文件并将其移到原始文件上(请参阅in perlfaq5 和 SO 帖子),或者可以通过脚本中的using -i ($^I)

        【讨论】:

        • 如果是单行,为什么不全部在一行。
        • @user3439894 术语“one-liner”代表可以直接从命令行执行的东西;它不必排成一行,而且通常不是(为了可读性)。此外,现代 shell 允许多行输入。这是在一行(长)行中编写和测试的。
        • @user3439894 它也是测试粗略版本代码的有用工具。如果满足,则可以编写适当的脚本,包括错误检查、选项、更精细的处理等。这就是它的意图。
        【解决方案5】:

        这可能对你有用(GNU sed 和 Bash):

        sed $'153r replacementFile\n;153,156d' file
        

        或者对于大多数 seds:

        sed -e '153r replacementFile' -e '153,156d' file
        

        或者如果您愿意:

        sed '153,156c\        let view:String.UTF8View = string.utf8\
            if let from = range.lowerBound.samePosition(in: view),\
               let to = range.upperBound.samePosition(in: view) {\
                offset.pointee += Int32(string[string.startIndex..<range.lowerBound].utf8.count)\
                length.pointee = Int32(view.distance(from: from, to: to))\
                return token\
            } else {\
                return nil\
            }' file
        

        注意第一个\ 保留前导空格,除最后一行之外的每一行都需要附加\。当空行由单个 \ 表示时,SO 中的降价格式不正确(因此我删除了替换的第二行),但大多数 shell 应该。

        【讨论】:

        • 你如何使用变量而不是实际的行号来做到这一点?
        • 最后一个效果很好,但它只将完美的输出打印到屏幕上,并不会替换文档中的文本。有关如何替换文档中的文本的任何提示?
        • 好的,我想出了一个可行的方法,但这是一个额外的命令。我仍然想知道你是否可以用你写的东西来做到这一点。 (我所做的是添加 '> newfile' 然后 'mv newfile file'
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-05-20
        • 2021-01-31
        • 2010-09-26
        • 2015-08-24
        • 2021-02-18
        • 2013-10-18
        • 2015-02-20
        相关资源
        最近更新 更多