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"
ただし、これは永久に実行されます。誰でも正しい構文で助けてくれますか?
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
)ソースファイルに出力されます。
私はgrepがあまり得意ではありません。ただし、問題は AWK コマンドを使用して解決できます。ただ見て
awk '/select/,/from/' *.sql
上記のコードは、select
の最初の出現からfrom
の最初のシーケンスまでになります。次に、返されたステートメントにcustomername
が含まれているかどうかを確認する必要があります。このために、結果をパイプすることができます。そして、再びawkまたはgrepを使用できます。
基本的な問題は、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のメソッドによって呼び出されるサブルーチンにラップする必要があります。