Bashは2つのパターン間のファイルから複数の行を別のファイルの内容に置き換えますか?

Bashは2つのパターン間のファイルから複数の行を別のファイルの内容に置き換えますか?

long.jsこのコンテンツを含む長いJavaScriptファイルがあります。

... 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コマンドのため、このループではパターンスペースは印刷されません。これは、/ END /行の前にcontent.jsファイルの内容を配置する効果があります。

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

関連情報