web-dev-qa-db-ja.com

複数行の検索に必要な正規表現(grep)

可能性のある複製:
ファイル内の複数行パターンを検索するにはどうすればよいですか?pcregrepを使用してください

grepを実行して、Word selectの後にWord customerNameが続き、その後にWord fromが続く* .sqlファイルを検索しています。このselectステートメントは複数の行にまたがることができ、タブと改行を含めることができます。

次のバリエーションをいくつか試しました。

$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"

ただし、これは永久に実行されます。誰でも正しい構文で助けてくれますか?

192
Ciaran Archer

Grepバリアントpcregrepをインストールする必要なく、grepで複数行検索を実行できます。

$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c

説明:

-PはgrepのPerl-regexpを有効にします(通常の拡張機能の強力な拡張機能)

-zは、行末で改行を抑制し、ヌル文字に置き換えます。つまり、grepは行末がどこにあるかを知っていますが、入力を1つの大きな行と見なします。

-oは一致のみを出力します。 -zを使用しているため、ファイル全体が1つの大きな行のようになっているため、一致する場合はファイル全体が印刷されます。このように、それはそれをしません。

正規表現で:

(?s)PCRE_DOTALLをアクティブにします。つまり、.は任意の文字または改行を検出します

\Nは、PCRE_DOTALLがアクティブになっている場合でも、改行以外を検索します

.*?は、最短一致モードで.を見つけます。つまり、できるだけ早く停止します。

^行の始まりを見つける

\1最初のグループへの後方参照(\s*)これは、メソッドの同じインデントを見つけようとしている

ご想像のとおり、この検索で​​はメインメソッドがC(*.c)ソースファイルに出力されます。

430
albfan

私はgrepがあまり得意ではありません。ただし、問題は AWK コマンドを使用して解決できます。ただ見て

awk '/select/,/from/' *.sql

上記のコードは、selectの最初の出現からfromの最初のシーケンスまでになります。次に、返されたステートメントにcustomernameが含まれているかどうかを確認する必要があります。このために、結果をパイプすることができます。そして、再びawkまたはgrepを使用できます。

150
Amit

基本的な問題は、grepが一度に1行ずつ機能することです。そのため、複数行にまたがるSELECTステートメントを見つけることができません。

2番目の問題は、使用している正規表現が、SELECTとFROMの間に表示される複雑さを処理しないことです。特に、コンマ、ピリオド(ピリオド)、空白だけでなく、引用符や内部に含まれるすべてのものも省略します引用符で囲まれた文字列。

Perlに一度に「段落」を読み取らせ、それに正規表現を適用する、Perlベースのソリューションを使用する可能性があります。欠点は、再帰検索に対処する必要があることです。もちろん、コアモジュール File :: Find を含む、それを行うモジュールがあります。

アウトラインでは、単一ファイルの場合:

$/ = "\n\n";    # Paragraphs

while (<>)
{
     if ($_ =~ m/SELECT.*customerName.*FROM/mi)
     {
         printf file name
         go to next file
     }
}

これは、File :: Findのメソッドによって呼び出されるサブルーチンにラップする必要があります。

7