2

ではsed、一致した後に複数行のテキスト ブロックを置き換えたいと思います。たとえば、「foo」と一致した後、その行番号が 0 であると仮定します。テキスト ブロックを -3 行目から +5 行目まで置き換えたいと考えています。 、つまり、一致する行の前の 3 行目と、一致する行の後の 5 行目の間のテキスト ブロックは、別のテキスト ブロックbar1\nbar2です。次の 2 つのシナリオでこれを実行できるようにしたいと考えています。

1) 置換されたブロックの後に一致する行を保持します。2) それらの行 -3 および +5 と一緒に一致する行を削除します。

私を助けてください。

ありがとうございました。

4

3 に答える 3

2

これはうまくいくかもしれません(GNU sed):

seq 31|sed 's/5/& match/' >/tmp/file
sed ':a;$q;N;s/\n/&/3;Ta;/match/!{P;D};:b;$bc;N;s/\n/&/8;Tb;:c;s/.*/bar1\nbar2/' /tmp/file
1
bar1
bar2
11
bar1
bar2
21
bar1
bar2
31
sed ':a;$q;N;s/\n/&/3;Ta;/match/!{P;D};h;s/\([^\n]*\n\)*\([^\n]*match[^\n]*\).*/\2/;x;:b;$bc;N;s/\n/&/8;Tb;:c;s/.*/bar1\nbar2/;G' /tmp/file
1
bar1
bar2
5 match
11
bar1
bar2
15 match
21
bar1
bar2
25 match
31

説明:

コマンドは 2 つの部分に分かれています。

  1. 前半は 3 行の移動ウィンドウを保持します。
  2. その後、matchさらに 5 行が追加されます。

詳細は次のとおりです。

  • :aループのプレースホルダーです
  • $qファイルの終わりに、パターン スペース (PS) 内のすべての行を出力します。
  • N次の行を PS に追加する
  • s/\n/&/33 番目の改行文字自体を置き換えます。これは、PS に 3 回線あることを確認するための計数装置です。
  • Ta前の置換がループ プレースホルダーに失敗した場合a
  • /match/!{P;D}見てmatch、最初の改行まで印刷に失敗した場合は、その行と改行を削除します(これにより、新しいサイクルが呼び出されます)。
  • :bこの時点で一致が見つかったループのプレースホルダーです。
  • $bcファイルの終わりの分岐がプレースホルダーに進む場合c
  • N次の行を PS に追加する
  • s/\n/&/88 番目 (3 前 5 前) の改行文字を単独で置き換えます。これは、PS に 5 行が追加されていることを確認するためのカウント デバイスです。
  • Tb前の置換がループ プレースホルダーに失敗した場合b
  • :cループのプレースホルダーです
  • s/.*/bar1\nbar2/PS を必要な文字列に置き換えます。

2 番目の 1 つのライナーは、match行のコピーを作成し、置換された文字列に追加します。

代替ソリューション:

sed -r ':a;$!N;s/[^\n]*/&/9;$!Ta;/^([^\n]*\n){3}([^\n]*match[^\n]*)\n.*/!{P;D};c\bar1\nbar2' file

sed -r ':a;$!N;s/[^\n]+/&/9;$!Ta;/^([^\n]*\n){3}([^\n]*match[^\n]*)\n.*/!{P;D};s//\bar1\nbar2\n\2/' file
于 2012-07-03T16:05:48.760 に答える
0

2 番目のシナリオで使用する 1 つの方法GNU sedですが、少し複雑に思えます (完全にコメントされています)。

infile次のコンテンツがあると仮定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

および内容script.sed:

## From first line until a line that matches the pattern (number ten in 
## this example), save lines in buffer and print each one when there are
## more than three lines between one of them and the line with the pattern
## to search.
0,/10/ {

        ## Mark 'a'
        :a

        ## If line matches the pattern break this loop.
        /10/ {
                bb
        }

        ## Until the pattern matches, if more than three lines (checking '\n') are
        ## saved, print the oldest one and delete it, because I only want to save last
        ## three.
        /\(\n[^\n]*\)\{3\}/ {
                P
                D
        }

        ## Append next line to pattern space and goto mark 'a' in a loop.
        N
        ba
}

## It should never match (I think), but it's a sanity check to avoid the
## following mark 'b'.
bc

## Here we are when found the line with the pattern, so read next five six
## lines and delete all of them but the sixth. If end of file found in this
## process none of them will be printed, so it seems ok.
:b
N;N;N;N;N
N
s/^.*\n//

## Here we are after deleting both '-3' and '+5' lines from the pattern matched,
## so only is left to print the remainder of the file in a loop.
:c
p
N
s/^.*\n//
bc

10コードの 5 行目と 11 行目のパターンを考慮して、このように実行します。必要に応じて変更してください。私の例では、行を削除する必要があります7,8,9,10,11,12,13,14,15:

sed -nf script.sed infile

次の出力で:

1
2
3
4
5
6
16
17
18
19
20
于 2012-07-03T13:50:23.987 に答える