ファイルの複数行パターンの後に複数行を追加するには?

ファイルの複数行パターンの後に複数行を追加するには?

特定のパターンの後に行セットを追加する必要があるファイルがあります。問題は、複数行のパターンを処理できないことです。

模様

<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>

このパターンの後に追加する行

<org.apache.jmeter.config.RestServerNodeElement guiclass="TestBeanGUI"
  testclass="org.apache.jmeter.config.RestServerNodeElement"
  testname="ATC_Test_Lab" enabled="true">
<stringProp name="TestPlan.comments"> </stringProp>
<stringProp name="authbasic">${Basic}</stringProp>
<stringProp name="authpassword">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>
<stringProp name="authuser">${User}</stringProp>
<stringProp name="extratag"></stringProp>

sed次のオプションでコマンドを試しましたが、-r機能しません

sed -i.bak '/^<stringProp
name="TestPlan.user_define_classpath"></stringProp>/{N;/\n</TestPlan>/{N;/\n<hashTree>/r
Config.jmx' $file

ファイルには、Config.jmxこのパターンの後に追加する必要がある行セットがあります。

間違い:-

sed: -e expression #1, char 116: unterminated `s' command

答え1

一部のスクリプト言語では、行全体を文字列として読み込んだり、埋め込み改行で正規表現置換を実行したりするなどの面倒なアプローチは避けましょう。

Awkのステートマシンメソッド各行を印刷します。必要な3行が連続して表示される場合、state変数は2にインクリメントされ、必要なブロックが印刷されます。他の入力の場合はstateゼロにリセットされます。

1
1 { print state }
state == 0 && /^<stringProp name="TestPlan.user_define_classpath"><\/stringProp>$/ {
  state++; next
}
state == 1 && /^<\/TestPlan>$/ {
  state++; next
}
state == 2 && /^<hashTree>$/ {
  print \
  "<org.apache.jmeter.config.RestServerNodeElement guiclass=\"TestBeanGUI\"\n" \
  "testclass=\"org.apache.jmeter.config.RestServerNodeElement\"\n" \
  "testname=\"ATC_Test_Lab\" enabled=\"true\">\n" \
  "<stringProp name=\"TestPlan.comments\"> </stringProp>\n" \
  "<stringProp name=\"authbasic\">${Basic}</stringProp>\n" \
  "<stringProp name=\"authpassword\">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>\n" \
  "<stringProp name=\"authuser\">${User}</stringProp>\n" \
  "<stringProp name=\"extratag\"></stringProp>\n"
}
1 {
  state = 0;
}

複数行の一致と出力TxR。ここであまり一般的ではないアプローチは、dataディレクティブを使用して入力ストリーム(文字列の怠惰なリスト)から2つのポイントをキャプチャし、次にLisp関数を使用してその2つのポイント(つまり一致ldiffするブロック)間のライン範囲を取得することです。次の方法で出力できますtprint

@(repeat)
@  (cases)
@    (data start)
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
@    (data end)
@    (do (tprint (ldiff start end)))
@    (output)
<org.apache.jmeter.config.RestServerNodeElement guiclass="TestBeanGUI"
  testclass="org.apache.jmeter.config.RestServerNodeElement"
  testname="ATC_Test_Lab" enabled="true">
<stringProp name="TestPlan.comments"> </stringProp>
<stringProp name="authbasic">${Basic}</stringProp>
<stringProp name="authpassword">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>
<stringProp name="authuser">${User}</stringProp>
<stringProp name="extratag"></stringProp>
@    (end)
@  (or)
@line
@    (do (put-line line))
@  (end)
@(end)

このアプローチでは、一致するコードブロックにいくつかの変数を追加し、次のような参照でキャプチャできるフラグメント@(output)と同じです。s/regexp/replace/静的単語ではなくテキストを抽出し、現在表示されているすべての場所にそのテキストをコピーする必要があるとします。\1\2&TestPlanTestPlan

@(repeat)
@  (cases)
@    (data start)
<stringProp name="@TYPE.user_define_classpath"></stringProp>
</@TYPE>
<hashTree>
@    (data end)
@    (do (tprint (ldiff start end)))
@    (output)
<org.apache.jmeter.config.RestServerNodeElement guiclass="TestBeanGUI"
  testclass="org.apache.jmeter.config.RestServerNodeElement"
  testname="ATC_Test_Lab" enabled="true">
<stringProp name="@TYPE.comments"> </stringProp>
<stringProp name="authbasic">${Basic}</stringProp>
<stringProp name="authpassword">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>
<stringProp name="authuser">${User}</stringProp>
<stringProp name="extratag"></stringProp>
@    (end)
@  (or)
@line
@    (do (put-line line))
@  (end)
@(end)

このバージョンを試してみましょう:

$ txr add.txr -
foo
foo
bar 
bar
blah
blah
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<org.apache.jmeter.config.RestServerNodeElement guiclass="TestBeanGUI"
  testclass="org.apache.jmeter.config.RestServerNodeElement"
  testname="ATC_Test_Lab" enabled="true">
<stringProp name="TestPlan.comments"> </stringProp>
<stringProp name="authbasic">${Basic}</stringProp>
<stringProp name="authpassword">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>
<stringProp name="authuser">${User}</stringProp>
<stringProp name="extratag"></stringProp>


blah
blah
blah
blah
<stringProp name="EvilPlan.user_define_classpath"></stringProp>  
</EvilPlan>
<hashTree>
<stringProp name="EvilPlan.user_define_classpath"></stringProp>
</EvilPlan>
<hashTree>
<org.apache.jmeter.config.RestServerNodeElement guiclass="TestBeanGUI"
  testclass="org.apache.jmeter.config.RestServerNodeElement"
  testname="ATC_Test_Lab" enabled="true">
<stringProp name="EvilPlan.comments"> </stringProp>
<stringProp name="authbasic">${Basic}</stringProp>
<stringProp name="authpassword">ENC(dsxxxxxxxxxxxWiu+FCzl5+A==)</stringProp>
<stringProp name="authuser">${User}</stringProp>
<stringProp name="extratag"></stringProp>
x
x
y
y
z
z

TestPlanに変更するとEvilPlan正常に動作し、コードを読み取ることができます。複数行のテキストがそのまま表示されます。その @キャラクターが出てきたら2倍に増やさなければなりませんが、そうでは@@ありません。

関連情報