いくつかの文字はリテラルとして扱われないようにエスケープする必要があるため、grep
にコマンドラインから使用する場合、「生の」文字列を供給することはできません。例えば:
$ grep '(hello|bye)' # WON'T MATCH 'hello'
$ grep '\(hello\|bye\)' # GOOD, BUT QUICKLY BECOMES UNREADABLE
私はprintf
を使用して文字列を自動エスケープしていました:
$ printf '%q' '(some|group)\n'
\(some\|group\)\\n
これにより、文字列のbashエスケープバージョンが生成され、バックティックを使用して、これをgrep呼び出しに簡単に渡すことができます。
$ grep `printf '%q' '(a|b|c)'`
ただし、これは明らかにこの目的ではありません。出力内の一部の文字はエスケープされず、一部は不要にエスケープされます。例えば:
$ printf '%q' '(^#)'
\(\^#\)
^
文字は、grep
に渡すときにエスケープしないでください。
生の文字列を受け取り、grepでパターンとして直接使用できるbashエスケープバージョンの文字列を返すcliツールはありますか?どうすれば純粋なbashでこれを達成できますか?
拡張正規表現構文を使用するためにgrep
を取得しようとしている場合、その方法はgrep -E
(別名egrep
)を使用することです。また、grep -F
(別名fgrep
)、およびGNU Coreutils、grep -P
。]の新しいバージョンについても知っておく必要があります。
背景:元のgrep
には、正規表現演算子のかなり小さなセットがありました。 Ken Thompsonの元の正規表現の実装でした。拡張されたレパートリーを備えた新しいバージョンは後で開発され、互換性の理由から別の名前が付けられました。 GNU grep
の場合、grep
として呼び出された場合は従来の基本的なRE構文を理解し、egrep
。egrep
の一部の構成体は、バックスラッシュエスケープを使用して特別な意味を導入することにより、grep
で使用できます。
その後、Perlプログラミング言語は形式をさらに拡張しました。この正規表現の方言は、ほとんどの新参者が誤ってgrep
もサポートすると期待しているようです。 grep -P
で、そうします。しかし、これはすべてのプラットフォームでまだ広くサポートされていません。
そのため、grep
では、次の文字に特別な意味があります:^$[]*.\
egrep
では、次の文字にも特別な意味があります:()|+?{}
。 (繰り返しの中括弧は元のegrep
にはありませんでした。)グループ化括弧は、\1
、\2
などによる後方参照も可能にします。
grep
の多くのバージョンでは、egrep
スペシャルの前にバックスラッシュを置くことでegrep
の動作を得ることができます。 \<\>
のような特別なシーケンスもあります。
Perlでは、\w
\s
\d
のような追加のエスケープが多数導入されました。 Perl 5では、正規表現機能が大幅に拡張され、貪欲でないマッチング*?
+?
など、非グループ化括弧(?:...)
、lookaheads、lookbehindsなどが追加されました。
...とは言っても、本当にegrep
正規表現をgrep
正規表現に変換したい場合は外部プロセスを呼び出さずにを試してください${regex/pattern/substitution}
egrep
特殊文字ごとに;ただし、これは文字クラス、否定された文字クラス、またはバックスラッシュエスケープを正しく処理しないことを認識してください。
正確な文字列を検索する場合は、
grep -F '(some|group)\n' ...
-F
は、grep
に、正規表現として解釈せずに、パターンをそのまま処理するように指示します。
(これはfgrep
としてもしばしば利用可能です。)
ユーザー指定の文字列でgrep -Eを使用すると、これでエスケープされます
ere_quote() {
sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*"
}
実行例
ere_quote ' \ $ [ ] ( ) { } | ^ . ? + *'
# output
# \\ \$ \[ \] \( \) \{ \} \| \^ \. \? \+ \*
これにより、正規表現に引用符付き文字列を安全に挿入できます。
例えばユーザーコンテンツから始まる各行を検索したい場合、ユーザーは。*として面白い文字列を提供します
userdata=".*"
grep -E -- "^$(ere_quote "$userdata")" <<< ".*hello"
# if you have colors in grep you'll see only ".*" in red
以前の回答は、ダッシュ(-)で始まる1つの重要なこと、つまり文字列を見逃しているため完全ではないと思います。したがって、これはしません動作します:
echo "A-B-C" | grep -F "-B-"
これは:
echo "A-B-C" | grep -F -- "-B-"