別のファイルの一致する2行の間に1つのファイルの内容を挿入するには?

別のファイルの一致する2行の間に1つのファイルの内容を挿入するには?

XMLファイルprocess.xmlがあり、ここにtmp.xmlの内容を挿入したいと思います。しかし、注意すべき点は、一致する2つのパターンの間にそれらを挿入する必要があることです。以下はprocess.xmlファイルの一部です。

$cat process.xml
...
<fork name="data">
      <path start="process_x" />
      <path start="process_y" />
      <path start="process_z" />
</fork>
...
...
<action name="process_x" />
....
....
</action>
<action name="process_z" />
....
....
</action>

tmp.xml ファイルの内容です。

$ cat tmp.xml
<path start="process_a" />
<path start="process_b" />

私の一致パターンは " process_z"と" </fork>"で、内容はこれらのパターンの間に貼り付ける必要があります。私が試したことは次のとおりです。

string=$(tac process.xml | grep -m1 -oP '(?<=path start="process_).*(?=" />)')
search="process_$string"
sed -e "/$search/ r tmp.xml" "process.xml"

ただし、内容はおよびに挿入されますtmp.xml。しかし、私はちょうどこのようにしている必要があります。forkactionfork

...
<fork name="data">
      <path start="process_x" />
      <path start="process_y" />
      <path start="process_z" />
      <path start="process_a" />
      <path start="process_b" />
</fork>
...
...

どんな助けでも大変感謝します。

ベストアンサー1

最後にもう一度表示したいと思います<path start="process_

次のことができます。

awk '
  /path start="process_/ {print saved $0; saved=""; n++; next}
  n {saved = saved $0 RS; next}
  {print}
  END{system("cat tmp.xml"); printf "%s", saved}' process.xml

path start="process_ただし、これは最後の発生から最後までファイルの一部をメモリに保存することを意味します。

または、次のコマンドを使用してファイル全体をメモリにインポートできます。

perl -0777 -pe 's/.*path start="process_.*?\n\K/<STDIN>/se
               ' process.xml < tmp.xml

</fork>空でない次の行でバリアントを確認してください。

perl -0777 -pe 's{.*path start="process_[^\n]*\n\K(?=\s*</fork>)}{<STDIN>}se
               ' process.xml < tmp.xml

インデントを並べ替え、欠落している場合は改行を追加するバリアントtmp.xml

perl -0777 -pe 's{(?s:.*)(^\h*).*path start="process_.*\n\K(?=\s*</fork>)}{
 $insert = <STDIN>;
 $indent = $1;
 $insert =~ s/^/$indent/gm;
 $insert =~ s/\n?$/\n/;
 $insert}me' process.xml < tmp.xml

を使用 -0777 -pe 'code' fileしてperl実行しcode$_そのfile内容を印刷します$_(ここで修正済みcode)。

これには置換コマンドがありますs{pattern}{replacement}flags

これらのすべてのコマンドで最後に現れるパターンを取得する秘訣はgreedyにつながります.*(ここではsフラグの下にあるため、改行文字も一致します)。欲が多いので^(フラグ付きの行の先頭m)、一連の水平スペース()が続くまで、できるだけ多くの文字を一致させようとします。\h*これをキャプチャしてからパターン$1(\h*)次の行の残り(.*今回はフラグがないのでs改行文字を食べません)の後に改行文字が続きます。

次に、これが一致するテキストの始まりであることを\K知らせるために1つを追加します。perl次に、改行文字の後に一連のスペース(\s*)が続くことを確認するプレビュー演算子があります</fork>

置換では、stdinからコンテンツを取得し、各行tmp.xmlの先頭にキャプチャされたインデントを挿入し、欠落している場合は末尾の改行を追加し、それを置換として使用します。


別の方法は、ファイルを2回処理することです。パターンが最後に現れる行番号を検索するために1回、ファイルを挿入するために2回目:

sed "$(awk '/path start="process_/{n=NR};END{print n}' < process.xml  
      )r tmp.xml" process.xml

または、次のように挿入することもできます</fork>

awk '/<\/fork>/{system("cat tmp.xml")};1' < process.xml

おすすめ記事