Bash 将两个模式之间的文件中的多行替换为另一个文件的内容?

Bash 将两个模式之间的文件中的多行替换为另一个文件的内容?

我有一个很长的 javascript 文件long.js,其中包含此内容

... more lines

ProcessCoverageController.createExampleQueries = function () {
    return [
        {
            title: '-- Select a query --',
            query: ''
        }, {
            title: 'No encoding',
            query: 'return avg($c)'
        }
    ];
};
ProcessCoverageController.$inject = [
    "$scope",
    "$log",
    "$interval",
    "Notification",
    "rasdaman.WCSService",
    "rasdaman.ErrorHandlingService"
];

... more lines

我想要做的是将 的内容替换return [ ... ];为具有以下内容的另一个文件(例如:content.js)的内容:

return [
        {
            title: 'title1',
            query: `query1 as asdasd asdasd`
        }, {
            title: 'title2',
            query: `query2 asdas dasd asd asda`
        }, {
            title: 'title3',
            query: `query3 asd asdasdasdasdasdasdasd`
        }, {
            title: 'title4',
            query: `query4 3asd asdasda sdasdasdasdasdad`
        }
    ];

有人可以给我一个提示,告诉我如何使用 sed 或 perl 来做到这一点吗(我尝试过看看,似乎 perl 是比 sed 更容易实现的工具)。但下面的示例无法正常工作:

#!/bin/bash

file_content=`cat content.js`
perl -i -p0e 's/ProcessCoverageController.createExampleQueries = function.*?ProcessCoverageController.\$inject/$file_content/s' long.js

答案1

该问题可以通过多种方式解决,其中一些方式如下所示。

注意:/BEGIN/ /END/ 我的选择是为了让它们清晰可见。将它们替换为您所需的边界标记。

sed 假设 /END/ 不应出现在最后一行。

sed -e '
  /BEGIN/,/END/!b
  //!d;/END/!b
  r content.js
  N
' long.js

在职的:

  • 按原样打印任何非块区域:/BEGIN/,/END/!b
  • 在块内,删除空腔://!d
  • 打印块的顶部边界:/END/!b
  • 使用 content.js 文件的内容填充输出缓冲区:r contents.js此处不打印到 stdout。
  • 读取下一行并附加到 /END/ 行。读取操作会触发输出缓冲区的刷新。请注意,由于 N 命令的原因,该循环中不会打印模式空间。这具有将 content.js 文件的内容放置在 /END/ 行之前的效果。

awk '
  BEGIN {
    repl = ARGV[1]
    ARGV[1] = ""
  }
  /BEGIN/ && !f {print;f=1}
  /END/ && f {
    while (getline t < repl > 0) {
      print t
    }
    f = 0
  }
  !f
' content.js long.js

perl -pe '
  $repl //= do{local $/;<STDIN>;};
  next unless my $e = /BEGIN/.../END/;
  $_ = $e =~ /E0/ ? $repl.$_
     : $e == 1 ? $_
     : s/.*//sr;
' long.js < content.js

contnt=$(< "content.js" sed -e 's/^/ /')

cat - <<eof | ed -s - long.js
1m1
/BEGIN/+1,/END/-1c
$contnt
.
?BEGIN?+1,/END/-1s/^ //
wq
eof

答案2

我从这个有用的答案中找到了一种使用 sed 的方法https://stackoverflow.com/a/49511949/2028440

sed -e '/ProcessCoverageController.createExampleQueries =/,/ProcessCoverageController.$inject/!b' -e '/ProcessCoverageController.$inject/!d;r content.js' -e 'd' long.js

相关内容