簡単な答えは次のとおりです。
grep "abc[^(?:def)]*ghi" ./testregex
これは、次のような testregex ファイルに基づいています。
abcghiabc
abcdefghi
abcghi
出力は次のようになります。
$ grep "abc[^(?:def)]*ghi" ./testregex
abcghiabc
abcghi
あなたのユースケースにマッピングすると、これは大まかに次のように翻訳されると思います:
grep -lri "stringA[^(?:stringB)]*stringC" ./*.sql
各文字列の間の「.*」を削除したことに注意してください。これは、除外しようとしている文字列と一致するためです。
更新: 元の質問で改行が呼び出されるようになったため、grep の -z フラグを使用します。
-z
行末の改行を抑制し、ヌル文字に置き換えます。つまり、grep は行末がどこにあるかを認識していますが、入力を 1 つの大きな行として認識します。
したがって:
grep -lriz "stringA[^(?:stringB)]*stringC" ./*.sql
私が最初にこのアプローチを自分で使用しなければならなかったとき、次の説明を書きました...
具体的には、「任意の文字、任意の回数、貪欲でない(したがって、後続の明示的なパターンに従う)、および SEQUENCE /> に一致しない」と一致させたいと考えていました。
最後の部分は、私が共有するために書いていることです:「シーケンス /> と一致しません」。「任意の文字」ロジックと組み合わせた文字シーケンスを使用したのはこれが初めてです。
私のターゲット文字列:
<img class="photo" src="http://d3gqasl9vmjfd8.cloudfront.net/49c7a10a-4a45-4530-9564-d058f70b9e5e.png" alt="Iron or Gold" />
私の最初の試み:
<img.*?class="photo".*?src=".*?".*?/>
これはオンライン正規表現テスターでは機能しましたが、実際の Java コード内で何らかの理由で失敗しました。試行錯誤の結果、すべての「。?」を置き換えることがわかりました。「[^<>] ?」で 成功しました。つまり、「任意の文字の非貪欲なマッチング」の代わりに、「< または > を除く任意の文字の非貪欲なマッチング」を使用できます。
しかし、これらの文字を含む代替テキストを見たことがあるので、これを使用したくありませんでした。私の特定のケースでは、文字シーケンス「/>」を除外シーケンスとして使用したいと考えていました。そのシーケンスが検出されたら、「任意の文字」の一致を停止します。
これは私のレッスンに私をもたらします:
パート 1: 文字シーケンスは (?:regex) を使用して実現できます。つまり、() 括弧を通常どおり文字シーケンスに使用しますが、シーケンスがターゲット グループとして一致しないようにするために、先頭に「?:」を追加します。したがって、"(?:/>)" は "/>" に一致し、"(?:/>)*" は "/>/>/>/>" に一致します。
パート 2: このような文字シーケンスは、単一の文字と同じ方法で使用できます。つまり、「[^(?:/>)]*?」です。シーケンス「/>」を除く任意の文字に何度でも一致し、貪欲ではありません。
それだけです。検索のキーワードは、「非キャプチャ グループ」と「負の先読み|後読み」です。後者の機能は、これまで行ってきたよりもはるかに深く、まだ理解していないフラグが追加されています。しかし、最初の理解により、当面のタスクに必要なツールが得られました。これは、私がしばらく疑問に思っていた機能です。あなたのツールセットで離れて。