これは、ここで尋ねられ、答えられた質問の拡張です:sed を使用して、パターンに最初に一致したファイル内のテキストを検索して置換します。
問題は、検索と置換を実行する必要があるが、のみの最初の出現の後に がpattern1
続きますpattern2
。ここでpattern3
検索と置換を実行する必要があります。
リンクされた質問のサンプル ファイルのバリエーションを使用します。
Server 'Test AB'
option type 'sa'
option port '1234'
option timeout '60'
Server 'Test AB'
option type 'sb'
option port '1234'
option timeout '60'
Server 'Test EF'
option type 'sa'
option port '1234'
option timeout '60'
Server 'Test GH'
option type 'sa'
option port '1234'
option timeout '60'
私はこれを必要とする:
Server 'Test AB'
option type 'sa'
option port '1234'
option timeout '60'
Server 'Test AB'
option type 'sb'
option port '9876'
option timeout '60'
Server 'Test EF'
option type 'sa'
option port '1234'
option timeout '60'
Server 'Test GH'
option type 'sa'
option port '1234'
option timeout '60'
最初の 2 つのServer
名前は同じです。 はoption type
サーバーごとに異なります。特定のServer
名前 ( Test AB
) を一致させ、次にoption type
( sb
) を一致させてから、ポート番号を変更する必要があります。
複数のパターンを論理的に連結する方法がわかりませんAND
。
何かヒントsed
やawk
解決策があれば教えてください(ただし、ハードコアなネックベアードを探している人には本物チャレンジとして、純粋な BASH 置換で実行してみてください。BASH 5 以降でも問題ありません。ありがとうございます。
答え1
sed
フォームでアドレス範囲を指定できますaddr1,addr2
。リンクされた回答では範囲が使用されています。範囲をネストする必要があります。
sed "
/^Server 'Test AB'$/,/^$/ {
/option type 'sb'/,/option port '/ s/option port '.*'/option port '2222'/
}" file
これは、 の行 (を含む) からServer 'Test AB'
次の空行 (を含む) まで、 内のコード を適用することを意味します{}
。
内部のコードは{}
、 を含む行 (および を含む行を含む) から を含む行option type 'sb'
(および を含む行を含む)までコマンドoption port '
を適用することを意味しますs/…/…/
。
コマンドのs/…/…/
意味は次のとおりです: 各行で、option port '.*'
( .*
0 個以上の文字に貪欲に一致する) の最初の出現を に置き換えますoption port '2222'
。
ノート:
幸いなことに、範囲を終了するために使用できる空行があります。空行がなければ、 から までの範囲を指定したくなるでしょう
Server
。Server
問題は、 から までの最初の範囲で、Server 'Test AB'
の次の出現に のServer
2 番目の出現が含まれることです。Server 'Test AB'
また、sed
同じaddr1,addr2
コードによって検出された範囲は重複できません。実際には、 の 2 番目の出現はServer 'Test AB'
新しい範囲の開始として扱われないため、このセクションの行では内部のコード{}
は実行されません。^
と は、$
それぞれ行の先頭と末尾のアンカーです。 ではこれらを使用しましたがServer 'Test AB'
、 では意図的に使用しませんでしたoption type 'sb'
。 必要に応じてコードを調整してください。データに一重引用符が含まれているため、二重引用符を使用しました。通常は
$
二重引用符でエスケープする必要がありますが、ここでは/
各引用符の直後に$
;があり$/
、これはシェル変数の有効な名前でもなければ、シェルが展開するものでもないため、エスケープする必要はありません$
。