web-dev-qa-db-ja.com

sedまたはexを使用して、ブロック(複数行コード)を新しいテキストブロック(コード)に置き換えるにはどうすればよいですか?

ファイル内の大きなテキストブロック(シェルスクリプトコード)を別のテキストブロックに置き換える必要があります。

sedを使用して複数行の文字列を置き換えるにはどうすればよいですか? 回答済み antak および Multi-line replace 回答済み- ブルース・エディガー

しかし、私はそれらを使用する際にいくつかの問題を抱えています。

  1. antak ファイル全体(1h;2,$H;$!d;g;)をバッファにストリーミングすることは、メモリが過負荷になるため、大きなファイルには推奨されないという彼の回答ですでに言及されています。

  2. sedをブロック機能で使用して、ブロック外のテキストを変更せずに保持できることを知っています。この機能を使いたい。でも使ったら

    sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
    

ストリームごとに新しいテキスト(コード)を繰り返し挿入します。したがって、ビジュアルブロックを1つのストリームとして作成する必要があります。以前に antak で提案されたものと似ていますが、ブロック用です(ファイル全体ではありません)。

  1. Bruce Edigerexで始まるaで始まる追加機能.(dot)で終わるように試すことができますが、新しいテキスト(コード)ドットで始まる行を含みます。これは、追加構文のドットと見なすことができます。この状況でどのように使用できますか?

  2. exdd '行数'は複数の行を削除する可能性がありますが、/ marker1 /と/ marker2 /の間に固定されていない(変化する)行数のブロックがある場合は置き換えられます新しいテキスト(コード)で、どうやってそれを行うのですか?

9
gibies

c hangeコマンドを使用することをお勧めします(これは基本的にd eleteとa ppendを組み合わせたものですが、appendは最後にのみ適用されます)ここで正確に必要な範囲の行):

sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename

ここではGNU sedのインプレース編集用の構文(-i)。そのcコマンドは、それ以外の点では標準的で移植性があります。 GNU sedは以下をサポートします:

sed '/marker1/,/marker2/cNew text 1\
New text 2' filename

非標準の拡張として。

置換テキストでは、改行文字とバックスラッシュ文字を(バックスラッシュで)エスケープする必要があります。

GNU sedを使用

3に一致する行から始まり、5に一致する行に続く行をNew Codeで置き換えるには:

$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8

/3/,/5/の範囲の行については、その行が5(これがグループの最後の行であることを意味する)と一致するかどうかをテストし、一致する場合は、置換を行ってNew Codeを挿入します。置換が行われた場合、tコマンドは、sedにコマンドの最後にジャンプするよう指示します(この場合、New Codeが出力されます)。そうでない場合、dコマンドはsedに行を削除するように指示します。

他のすべての行は通常どおり印刷されます。

ファイルを適切に変更するには、-iオプションを使用できます。

sed -i.bak '/3/,/5/{/5/ s/.*/New Code/; t; d}' file

Awkの使用

Awkを使用して同じことを行うには:

$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8

Awkコマンドは、/3/,/5/の範囲の行を特別に扱います。その範囲の行について、fがゼロかどうか(つまり、!fがtrueかどうか)をテストし、ゼロの場合はNew Codeを出力してfを1に設定してからスキップします残りのコマンドとnext行にジャンプします。

/3/,/5/の範囲外の行の場合、ジャンプは行われず、1によって行が出力されます。より詳細には、1は条件です。 1はゼロではないため、条件はtrueと評価されます。条件に関連付けられているアクションがないため、行を印刷するというデフォルトのアクションが実行されます。したがって、1は、印刷行の省略形です。

ファイルをその場で変更するには、-i inplaceオプションをGNU awk 4.1以上で使用できます。

awk -i inplace '/3/,/5/{if (!f)print "New Code"; f=1; next} 1' file
8
John1024

上記の議論に基づいて、私はexを使用した解決策を考え出します

seq 15 > test1.txt
ex test1.txt << EOEX
/^7/,/^9/c
abcd
123
.xyz
hfr4
.
w!
q
EOEX
cat test1.txt

上記は与える

1
2
3
4
5
6
abcd
123
.xyz
hfr4
10
11
12
13
14
15

g-man に変更コマンドを認識させ、ドットについての説明をお願いします。 sedexはどちらも、変更コマンド(削除コマンド、追加コマンドなど)とほぼ同じ構文を共有しています。

1
gibies