6

以下のように、 pattern1 の後、 pattern 2 と pattern3 の間にあるファイルから行を削除する必要があります。

aaaaaaaa 
bbbbbbbb
pattern1   <-----After this line
cdededed
ddededed
pattern2
fefefefe   <-----Delete this line
efefefef   <-----Delete this line
pattern3
adsffdsd
huaserew

awk、sed、または perl を使用してこれを行う方法を提案してください。

4

5 に答える 5

5
sed '/pattern1/,${ /pattern2/,/pattern3/{/pattern2/b; /pattern3/b; d;} };' file

フォーマット:

/pattern1/,$ {
    /pattern2/,/pattern3/ {
        /pattern2/b;
        /pattern3/b; 
        d;
    } 
}

説明:

  • /pattern1/,$pattern1ファイルの末尾までの行の範囲です
  • /pattern2/,/pattern3/pattern2はとの間の行の範囲ですpattern3
  • /pattern2/b;範囲に含まれるand行を/pattern3/b;スキップします ( sed faqを参照)pattern2pattern3
  • d範囲内の他の行を削​​除します

アップデート

コメントから、内側のブロックを次のように書き換えることができます。

//!d

どこ:

  • //(空のパターン) は、最後に使用された正規表現 (この場合は両方pattern2pattern3
  • !パターンに一致する行以外のすべてに適用されるように、次のコマンドを反転します
  • dこれらの行を削除します

したがって、書き直された完全なパターンは次のとおりです。

/pattern1/,$ {
    /pattern2/,/pattern3/ {
        //!d
    } 
}
于 2012-06-09T10:12:33.117 に答える
4

awk をステート マシンのように使用します。

awk '
    BEGIN {print_line = 1}
    /pattern1/ {consider = 1}
    consider && /pattern2/ {print_line = 0; print}
    consider && /pattern3/ {print_line = 1}
    print_line {print}
' filename
于 2012-06-09T10:45:18.810 に答える
2

perl を使用してコマンド ラインで迅速な解決策を探している場合、これはflip-flopオペレーターにとって理想的なケースです。さて、この質問を極端なケースで解釈できる方法は 2 つありpattern1ますpattern2

  1. パターン1がパターン2 の後、パターン 3 の前にある場合、パターン 1とパターン3 の間のすべてを削除します

  2. または、pattern1がpattern2の後、pattern3 の前にある場合、別のpattern1が表示されない限り何もしません。

始める前に、perl の引数に注意してください-p

-n                assume "while (<>) { ... }" loop around program
-p                assume loop like -n but print line also, like sed

さて、最初に、私はあなたに..

perl -pe'$x ||= /7/; $_= "" if /5/ .. /8/ and $x' <(seq 1 10)
1
2
3
4
5
6
9
10

$x ||= /7/:のとき$xの戻り値に設定します。一致すると戻ります。これは、最初の一致で true に設定されることを意味し、その性質上、変数が既に true になっている場合は設定されません。/7/$xfalse/7/true$x||=

次に$_ = ''、範囲が と の間/5/にあり/8/、すでに$xtrue に設定されている場合に設定します。短絡が機能する方法を覚えておいてください:と評価される場合にのみa && b実行することを意味します。この場合、単に評価するという事実だけで、フリップフロップ演算子の状態が設定されます。これが私たちが望んでいることです。ただし、既に表示されている場合にのみ発生させたいと考えています。batruea$_ = ''7

さて、質問の 2 番目の解釈では、順序を入れ替えてください...

perl -pe'$x ||= /7/; $_= "" if $x and /5/ .. /8/' <(seq 1 10)

これにより、全範囲が出力されます。Perl は/5/、 が見つかるまで検索を開始しません/7/。私たちのシーケンシャル範囲では、それは起こりません。

ところで、これらの回答のいくつかを恥ずべきことにするために、スペースの多くは必要ありません...

perl -pe'$x||=/2/;$_=""if$x&&/5/../8/' # secksey
于 2012-06-09T14:01:11.447 に答える
1

これはあなたのために働くかもしれません:

sed '/pattern1/,$!b;/pattern2/,/pattern3/!b;//!d' file
于 2012-06-09T13:15:04.963 に答える
1

ロゼッタ ストーンの完成:

perl -ne '++$saw_pattern1 if /pattern1/;
          $inside = ($saw_pattern1 && /pattern2/) .. /pattern3/;
          print unless $inside && ($inside > 1 && $inside !~ /E0$/)' \
  input

このコードは、Perl の..範囲演算子を利用しています。

スカラー コンテキストで..は、ブール値を返します。演算子はフリップフロップのように双安定であり、sedawk、およびさまざまなエディターの行範囲 (コンマ) 演算子をエミュレートします。各..演算子は、それを含むサブルーチンへの呼び出し間であっても、独自のブール状態を維持します。左オペランドが false である限り、false です。左のオペランドが true になると、範囲演算子は右のオペランドが true になるまで true のままになり、その後、範囲演算子は再び false になります。次に範囲演算子が評価されるまで false になりません…</p>

演算子が false 状態にある間は右オペランドは評価されず、演算子が true 状態にある間は左オペランドは評価されません。||優先順位はやよりも少し低くなり&&ます。返される値は、false の場合は空の文字列、true の場合はシーケンス番号 (1 から始まる) のいずれかです。シーケンス番号は、検出された範囲ごとにリセットされます。範囲内の最後のシーケンス番号には文字列E0が追加されます。これは数値には影響しませんが、エンドポイントを除外する場合に検索するものを提供します。シーケンス番号が 1 より大きくなるのを待つことで、開始点を除外できます。

于 2012-06-09T12:04:21.550 に答える