awkで範囲モードの範囲を制限する方法はありますか?

awkで範囲モードの範囲を制限する方法はありますか?

私は以下からインスピレーションを得て、ファイルセット内のすべてのSQL文をawk見つけるために範囲パターンを使用しようとしています。selectこのstackoverflowの答え

awkマニュアルから:

表現の形をpattern1, pattern2指す。範囲モード。一致するレコードで始まり、pattern1一致するレコードを pattern2含むすべての入力レコードを一致させます。

私の最初の試みは

awk '/select/,/from/' *

この場合、*さまざまなファイルがたくさん表示されます。

これにより、selectHTMLタグに誤ったヒットが返されたため、次のようにコマンドを改善しました。

awk '/[^<]select[^>]/,/from/' *

これにより、ほとんどのクリックが削除されるようです。

ただし、コメントに「select」という単語が表示されるため、まだいくつかの誤ったヒットが発生し、これらのヒットは、「from」の最後のヒットまたはファイルの終わりより前の各ヒットから多くのラインノイズにつながります。私が望むのは、「select」と「from」の間に10行以上がある場合、範囲パターンが一致を登録しないことです。

pattern1私の質問は:一致と一致の間の行数が指定されたしきい値をpattern2超えると、範囲パターンが一致しないようにすることはできますか?では、どうすれば達成できますか?

答え1

スコープモードは便利ですが、柔軟性はありません。これを使用しないで、代わりに変数間または変数間の状態を維持してください。 awkスクリプト/select/,/from/は次のとおりです。

/select/ {printing = 1}
printing {print}
/from/ {printing = 0}

範囲を複数の行に制限するには、表示された行のカウンタを保持し、表示するかどうかを判断するまで出力を累積します。

/select/ {select_text = $0; select_line_count = 1;}
select_line_count {select_text = select_text "\n" $0}
/from/ {if (select_line_count <= 10) {print select_text; print}
        select_line_count = 0}

select行の先頭(スペースを除く)に含める必要があり、その後にスペースが続くようにパターンを最適化する必要があります。/^[\t ]*select($|[\t ])/

答え2

/pattern1/,/pattern2/{}このような状況が発生した場合は、実行するブロックを追加して必要に応じて条件を拡張できます。

たとえば、50から70の数字を印刷しながら、各ブロックの最初の5つの一致のみを印刷する方法を見てみましょう。

$ seq 200 | awk '/50/,/70/ {if ($0~/50/) {c=0}; if (c++ <= 5) print}'
50
51
52
53
54
55
150
151
152
153
154
155

あなたの場合は、次のように言いたいことがあります。これにより、一致する最初の10行が印刷されます。

awk '/[^<]select[^>]/,/from/ {if (c++ <= 10) print}' *

より複雑な解決策は、これらすべての出力を保存してENDブロックに印刷することです。これにより、特定の行だけでなくブロック自体も制御できます。データを配列などに保存します。

関連情報