パターンに一致する各連続行シーケンスの最初の行のみを保持します。

パターンに一致する各連続行シーケンスの最初の行のみを保持します。

2つ以上の連続する行に特定のパターンが含まれている場合は、一致する行をすべて削除し、最初の行のみを保持します。

次の例では、2つ以上の連続する行に「論理IO」が含まれている場合は、一致するすべての行を削除し、最初の行は維持する必要があります。

入力ファイル:

select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
testing logical IO 500
handling logical IO 49
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
testing logical IO 12

結果ファイル:

select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346

答え1

使用awk:

awk '/logical IO/ {if (!seen) {print; seen=1}; next}; {print; seen=0}' file.txt 
  • /logical IO/ {if (!seen) {print; seen=1}; next}行が含まれていることを確認し、logical IO変数がseenfalseの場合、つまり前の行が含まれていない場合は、行をlogical IO印刷して設定し、seen=1次の行に移動します。それ以外の場合は、前の行がすでに含まれているので、次の行に移動します。logical IO

  • 他の行の場合は、{print; seen=0}行とセットを印刷します。seen=0

例:

$ cat file.txt 
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
testing logical IO 500
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346
parsing logical IO 346
testing logical IO 12

$ awk '/logical IO/ {if (!seen) {print; seen=1}; next}; {print; seen=0}' file.txt 
select * from test1 where 1=1
testing logical IO 24
select * from test2 where condition=4
parsing logical IO 45
select * from test5 where 1=1
testing logical IO 24
select * from test5 where condition=78
parsing logical IO 346

答え2

そしてsed

sed '/logical IO/{x;//!{g;p;};d;};//!h' infile

仕組み:

sed '/logical IO/{         # if line matches
x                          # exchange hold space w. pattern space
//!{                       # if whatever was in the hold buffer doesn't match
g                          # overwrite pattern space with hold space content
p                          # print current pattern space
}
d                          # delete
}
//!h                       # if line doesn't match, copy over the hold space
' infile

答え3

内部にTxR状態変数を変更せずにこれを表現できます。ファイル内の特定の場所で2つの分岐方法を使用して、複数行のパターンマッチングを実行できます。検索文字列を含む1つ以上の連続する行を一致させて最初の行を印刷するか、1行を一致させて印刷します。 1つの可能なアプローチは次のとおりです。

@(repeat)
@  (cases)
@    (collect :gap 0 :mintimes 1)
@line
@      (require (search-str line "logical IO"))
@    (end)
@    (do (put-line (first line)))
@  (or)
@line
@    (do (put-line line))
@  (end)
@(end)

ランニング:

$txr 最初のログ IO.txr データ
1 = 1のtest1で*を選択します。
論理IO 24テスト
SELECT * FROM test2 ここで条件=4
論理IO解析45
1 = 1のtest5で*を選択します。
論理IO 24テスト
SELECT * FROM test5 ここで条件=78
論理IO 346の解析

@(repeat)変数バインディングを収集せずにデータを繰り返すプロシージャを構築します。この構成を見ると、通常、反復中にいくつかの副作用が発生することがわかります。この場合は出力です。

内部的には、別々のケースで構成されたマルチパスマッチングという構造が@(repeat)あります。 2番目の四半期の代替ケースは、単に1行に一致します。次のガイドラインはこの行を印刷します。@(cases)@(or)@line@(do (put-line (first line)))

組織の主な部門@(cases)は資料を収集することです@(collect)。の要件によると、一致は連続している必要があり、要件に応じて少なくとも:gap 01つの一致が必要です:mintimes 1。コレクションの本文は、変数にバインドされた1行と一致しますline。その後、@(require ...)行に部分文字列が含まれていないと失敗するアサーションがあります"logical IO"。したがって、一致しない行を検出すると、コレクションをスキップするのを:gap 0防ぐため、コレクションは停止します。一致する行はポップlineリストとして暗黙的に収集されますcollect(コレクション内にバインドされた変数は自動的にコレクションの外側のリストになり、複数の反復でバインドされたすべての値を含みます)。必要に応じて最初のものだけを印刷し、残りは抑制します。

これらの 2 つ@lineの一致は互いに関係がありません。line異なる範囲の変数をバインドします。

別のアプローチは、TXR Lispの怠惰なリストを使用していくつかの機能的プログラミングを実行することです。

[(opip (partition-by (do cond
                       ((search-str @1 "logical IO") t)
                       (t @1)))
       (mapcar* first)
       put-lines)
 (get-lines)]
$txr 最初のログ IO.tl

演算子は、opip関数パイプラインを構築するための構文砂糖です。その引数は、op暗黙的に番号付きの引数で匿名関数を生成するための構文:マクロとして扱われます。

完全な形式は [(opip...)(get-lines)] です。これは、「結果関数を呼び出しopipて結果を(get-lines)引数として渡す」ことを意味します。これは(get-lines)標準入力ストリームを怠惰な文字列のリストに変換します。 (それの「反対」はput-linesそれが現れるということです)。

次に、パイプラインでpartition-by(lazy!)を使用して、行リストをそのパーティションであるリストリストに変換します。分割条件は、含まれる各行がlogical IOシンボルにマップされ、t他のすべての行が自分だけにマップされることです。これは、連続した行が1つlogical IOのパーティションとして表示され、他のすべての行が長さ1のパーティションとして表示されることを意味します。今、このデータでやるべきことは、各パーティションを最初のエントリにマッピングし、それを渡してダンプ結果を(mapcar* first)渡すことだけです。put-lines

私たちはすべてが怠惰に実行され、実際に実行されることを望んでいるmapcar*ので、これを使用します。出力リストを繰り返すと、lazyから項目を取得し、結果リストからその行を読み取るためにI / Oが発生します。mapcarput-linesput-linesmapcar*partition-by(get-lines)

正規表現を誤って使用すると、ダンプされるmapcar前に出力全体がメモリにビルドされるという問題が発生する可能性があります。これは、大容量ファイルの悪い信号です。

関連情報