grep
とsed
はどちらも、デフォルトで「基本正規表現」(「BRE」)を使用するものとして説明されています。 BREはよく説明されています ここ 。
しかし、この出力を考慮してください:
_# echo ' aaaaa ' | grep '\(aaaaa\|bbbbb\)'
aaaaa
# echo ' aaaaa ' | sed '/\(aaaaa\|bbbbb\)/ s/ /_/g'
aaaaa
_
最初のコマンドでは、出力がgrep
を渡したため、\( ... \| ... \)
構文は_(X OR Y)
_として明確に機能しました 。
2番目のコマンドでは、スペースが変更されなかったため、\( ... \| ... \)
構文は明らかに_(X OR Y)
_として機能しません。アンダースコアに。
(対照的に、bothコマンドは_\+
_を「1回以上の繰り返し」として認識します)
何が起こったの? FreeBSDには2つのフレーバーのBREがあるように見えるのはなぜですか。一方は構文を認識し、もう一方は認識しません。
より深い疑問は、多くのプロジェクトが他のUNIXライクなシステムへの移植性を提供するためにBREを検討することです。しかし、これは、BREが個々のプラットフォーム内で同じでなければ、プラットフォーム間で同じである可能性は低いことを示唆しています。あれ?
リンク先の記事の説明が間違っています。
実際のPOSIX定義 は次のように述べています。
エスケープされていない<backslash>( '\')が前にある通常の文字の解釈は、以下を除いて未定義です。 [
(){}
、数字および括弧式内]
また、通常の文字は、BRE特殊文字.[^$*
およびバックスラッシュ自体を除いて、任意のものとして定義されます。
そのため、そのページのクレームとは異なり、\+
はBREで未定義であり、\|
も未定義です。
一部の正規表現の実装では、これらをERE +
および|
と同じように定義していますが、特にGNU ones。ですが、それを当てにしないでください。代わりに機能。
もちろん、ここでの問題は、ERE代替演算子|
がBREにまったく存在せず、ERE +
と同等のものが醜く醜いことです(\{1,\}
です)。したがって、おそらく代わりにEREを使用する必要があります。
$ echo ' aaaaa ' | sed 's/aaaaa|bbbbb/_/g'
aaaaa
$ echo ' aaaaa ' | sed -E 's/aaaaa|bbbbb/_/g'
_
$ echo ' aaaaa ' | sed -r 's/aaaaa|bbbbb/_/g'
_
$ echo ' aaaaa ' | sed -E '/(aaaaa|bbbbb)/ s/ /_/g'
____aaaaa___
$ echo ' aaaaa ' | sed -E '/aaaaa|bbbbb/ s/ /_/g'
____aaaaa___
or
はBRE(基本正規表現)ではありません。 extendedBREには-E
を指定する必要があります。
GNUまたはBSD Sed)==の Regex代替/または演算子(foo | bar)を参照
なぜgrepは機能したのですか?
grep を使用して、使用するパターンの種類を選択できます。
-E, --extended-regexp PATTERN is an extended regular expression
-F, --fixed-strings PATTERN is a set of newline-separated strings
-G, --basic-regexp PATTERN is a basic regular expression
-P, --Perl-regexp PATTERN is a Perl regular expression
-e, --regexp=PATTERN use PATTERN as a regular expression
これらのスイッチを使用すると、grep
が実際にデフォルトでBREを実行し、OP式がEREで失敗することがわかります。
$ echo ' aaaaa ' | grep '\(aaaaa\|bbbbb\)'
aaaaa
$ echo ' aaaaa ' | egrep '\(aaaaa\|bbbbb\)'
$ echo ' aaaaa ' | grep -E '\(aaaaa\|bbbbb\)'
$ echo ' aaaaa ' | grep -G '\(aaaaa\|bbbbb\)'
aaaaa
$ echo ' aaaaa ' | grep -G 'aaaaa\|bbbbb'
aaaaa
$ echo ' aaaaa ' | grep -G 'aaaaa|bbbbb'
$ echo ' aaaaa ' | grep -E 'aaaaa|bbbbb'
aaaaa
$ echo ' aaaaa ' | grep -E 'aaaaa\|bbbbb'
$ echo ' aaaaa ' | grep -G 'bbbbb\|aaaaa'
aaaaa
$ echo ' aaaaa ' | grep -E 'bbbbb\|aaaaa'
$ echo ' aaaaa ' | grep -G 'bbbbb|aaaaa'
$ echo ' aaaaa ' | grep -E 'bbbbb|aaaaa'
aaaaa
grep および sed 参照 re_format(7) の両方が明確に述べています:
廃止された(「基本的な」)正規表現は、いくつかの点で異なります。 `| '通常の文字であり、その機能に相当するものはありません。
しかし、「パイプをエスケープする」と、実際に機能が得られるようです。それは確かにそれに匂いがあります。さらに、その球場に最近の破損があるようです regex(3):最近のBRE回帰をカバーするテストを追加する を参照してください。
そして、libcの regex を置き換える作業がいくつかあるようです。
チャールズ・ダフィーが下にコメントするように
一部のツールは非標準の拡張機能を実装しているため、バックスラッシュを使用して、BREコンテキストでEREのみの動作を行うことができます。
私はFreeBSDの非常に優れたドキュメントに慣れています。これは、これが意図されているが文書化されていないのか、それとも破損しているのか、私にはわからないということです。