タブ文字を一致させるために grep 式で $'string' を使用する必要があるのはなぜですか?

タブ文字を一致させるために grep 式で $'string' を使用する必要があるのはなぜですか?

このコードを使用すると:

echo -e '\t\t\tString' | grep '^[\t]*String'

一致しないため結果は空白になりますが、次のようになります。

echo -e '\t\t\tString' | grep $'^[\t]*String'

動作します。私は、スクリプトやターミナルで最初の行のコードを 100 回以上使用しましたが、そのように "$" 文字を使用したことは一度もありません。常に動作しているように見えます。最近何か変更があったのでしょうか? なぜ "$" 文字が必要なのでしょうか? それとも、私が何か間違っているのでしょうか?

答え1

ANSI-C 引用符

Bashのマニュアルによると、これはANSI-C 引用符マニュアルにはこう書かれています:

形式の単語$'文字列'特別に扱われます。単語は文字列に展開され、バックスラッシュでエスケープされた文字は ANSI C 標準の指定に従って置き換えられます。

実際には、これは が'\t'タブ文字に展開されないことを意味しますが、$'\t'は展開されます。出力は を使用した場合と同等ですecho -eが、 を必要とせずに文字列を使用する場所であればどこでも使用できます。コマンド置換

GNU sed のようなユーティリティは独自のエスケープ文字の展開を実行しますが、GNU grep は実行しません。ANSI-C 引用符付き文字列内のエスケープ文字を展開するのは、grep ではなく Bash シェルです。ANSI-C 引用符がないと、投稿した正規表現には入力に一致するタブ文字が含まれません。

答え2

正規表現には単一のタイプがないことにおそらく気付くでしょう。少なくともbasic regular expressionsまたはBRE(場合によっては のみRE)、extended regular expressionsまたはEREperl compatible regular expressionsまたは がありますPCRE。これらの言語はすべて、わずかに異なる構文を使用します。 の現在のバージョンはGNU grep3 つすべてをサポートし、 はBREデフォルトです。 にはオプションを、 オプションには をERE使用する必要があります。基本および拡張正規表現ではバックスラッシュは意味を失い、バックスラッシュまたは文字 t のいずれかに一致するため、例は でのみ機能します。おそらく、 をデフォルトでサポートする他の言語でそのパターンを使用していたのでしょう。これらは最も強力なバージョンなので、それは理にかなっています。あるいは、どこかで使用していたのかもしれません。-EPCRE -P-P[\t]PCREalias grep='grep -P'

答え3

最初の行は、 を省略すると機能します^。 機能したかもしれませんが、想定したようには機能しませんでしたか?grepの挙動がこのような重要な点で変更されたとは思えません。

echoデフォルトではエスケープ シーケンスを変換しません。-eそのためには が必要です。シェルの場合も同様です。$'...'シェルがエスケープ シーケンスを使用するようにする必要があります。

関連情報