Grep: アスタリスク (*) が常に機能するわけではない

Grep: アスタリスク (*) が常に機能するわけではない

次の内容を含む文書を grep すると:

ThisExampleString

...式This*Stringまたは の場合*String、何も返されません。ただし、This*は期待どおりに上記の行を返します。

式が引用符で囲まれているかどうかは関係ありません。

アスタリスクは任意の数の不明な文字を示すものだと思っていましたが、なぜ式の先頭にある場合にのみ機能するのでしょうか。これが意図された動作である場合、式 と の代わりに何を使用すればよいのでしょうThis*String*String

答え1

アスタリスク正規表現「前の要素が 0 回以上一致する」という意味です。

の特定のケースでは、「ねえ、grep、単語 に小文字が0 回以上続き、その後に単語 " が続くgrep 'This*String' file.txtものを一致させてください」と言っていることになります。には小文字がどこにも見つからないため、grep は を無視します。ThisStringsExampleThisExampleString

の場合grep '*String' file.txt、「grep、単語「」の前の空文字列(文字通り何もない)に一致させてくださいString」と言っていることになります。もちろん、 はそうThisExampleString読むべきではありません。(他の意味の可能性--フラグありとフラグなしの両方でこれを試すことができます-Eが、いずれの意味もここで本当に望んでいるものとはまったく異なります。

.が「任意の 1 文字」を意味することがわかっているので、次のように実行できますgrep 'This.*String' file.txt。これで、grep コマンドはこれを正しく読み取ります。This任意の文字 (ASCII 文字の選択と考えてください) が任意の回数繰り返され、その後に が続きますString

答え2

*BRE 1、ERE 1、および PCRE 1のメタ文字は、前にグループ化されたパターンの 0 回以上の出現 (グループ化されたパターンが*メタ文字の前にある場合)、前の文字クラスの 0 回以上の出現 (文字クラスがメタ*文字の前にある場合)、または前の文字の 0 回以上の出現 (グループ化されたパターンも文字クラスもメタ*文字の前にない場合) と一致します。

これはThis*String、パターン内で、*メタ文字の前にグループ化されたパターンまたは文字クラスがないため、*メタ文字が前の文字 (この場合は文字) の 0 回以上の出現に一致することを意味しますs

% cat infile               
ThisExampleString
ThisString
ThissString
% grep 'This*String' infile
ThisString
ThissString

任意の文字の 0 回以上の出現に一致させるには、任意.の文字に一致するメタ文字の 0 回以上の出現に一致させる必要があります。

% cat infile               
ThisExampleString
% grep 'This.*String' infile
ThisExampleString

BRE と ERE のメタ文字*は常に「貪欲」です。つまり、最も長い一致と一致します。

% cat infile
ThisExampleStringIsAString
% grep -o 'This.*String' infile
ThisExampleStringIsAString

これは望ましい動作ではないかもしれません。そうでない場合は、grepの PCRE エンジンをオンにして (-Pオプションを使用)、メタ文字を追加します。メタ文字をおよびメタ文字?の後に配置すると、それらの貪欲さが変更される効果があります。*+

% cat infile
ThisExampleStringIsAString
% grep -Po 'This.*?String' infile
ThisExampleString

1: 基本正規表現、拡張正規表現、Perl互換正規表現

答え3

ここで見つかった説明の1つリンク:

アスタリスク " *" は、正規表現とワイルドカードで同じ意味を持つわけではありません。これは、先行する単一の文字、または [0-9] などの表現に適用される修飾子です。アスタリスクは、その前にある 0 個以上の文字と一致します。したがって、[A-Z]*は任意の数の大文字 (0 個を含む) と一致しますが、[A-Z][A-Z]*は 1 つ以上の大文字と一致します。

答え4

*シェルとしても特別な意味を持つグロビング文字(「ワイルドカード」)および正規表現としてメタ文字両方を考慮する必要がありますが、引用正規表現を使用すると、シェルがそれを特別扱いするのを防ぎ、変更せずに渡すことができます。grep。 それでもちょっと概念的には似ていますが、*シェルにとっての意味は にとっての意味とはまったく異なりますgrep

初めシェルは*ワイルドカードとして扱います。

あなたが言った:

式が引用符で囲まれているかどうかは関係ありません。

それは、コマンドを実行するときにどのディレクトリにどんなファイルが存在するかによって異なります。ディレクトリ区切り文字を含むパターンの場合/、システム全体に存在するファイルによって異なる場合があります。常に引用grep--andの正規表現一重引用符通常は最高です--ない限りあなたは大丈夫だと確信しています9種類の驚くべき変化の可能性シェルはそれ以外の場合は前にコマンドを実行しますgrep

シェルが*引用は「0個以上の任意の文字」を意味し、それを含む単語を置き換えるパターンに一致するファイル名のリスト。(.パターン自体がで始まっていない限り、で始まるファイル名は除外されます。. またはいずれにしても、シェルにそれらを含めるように設定した場合。これはグロビング--そして名前によってもファイル名の拡張そしてパス名の拡張

通常は、grep最初に一致したファイル名が正規表現として扱われることになります。たとえそれが人間の読者にとって明らかに正規表現であるとしてもです。ない正規表現として意味されますが、globから自動的にリストされた他のすべてのファイル名は、ファイルとして扱われます内部一致を検索する です。(リストは表示されません。不透明に に渡されますgrep。) 実際には、このようなことが起こることは望ましくありません。

その理由は時々問題ではありません。少なくともあなたの場合はこれまでのところそれはそうではなかった--それは*放っておかれる以下のすべてが当てはまる場合:

  1. あったいいえ名前が一致するファイル。 ...またはシェルで glob を無効にしています。通常はset -fまたは同等の を使用set -o noglobします。ただし、これはまれなケースであり、おそらく自分で無効にしたことに気付くはずです。

  2. *一致するファイル名がない場合にはそのままにしておくのがデフォルトの動作であるシェルを使用しています。これは、あなたが使用しているBashの場合です。おそらく使用していますが、すべてのBourneスタイルのシェルでそうではありません。(たとえば、人気のあるシェルZshのデフォルトの動作では、globは(ア)拡大または(ロ)エラーが発生します。...またはシェルのこの動作を変更しました。変更方法はシェルによって異なります。

  3. あなたはやってないさもないとシェルにグロブを置き換えるように指示しました何もない一致するファイルがない場合、またはこの状況でエラーメッセージを表示して失敗しないようにします。Bashでは、またはを有効にすることで実行できますnullglobfailglob シェルオプション、 それぞれ。

2 番目と 3 番目は頼りになる場合もありますが、1 番目はほとんど頼りになりません。grep現在は機能している引用符で囲まれていないパターンのコマンドでも、別のファイルがある場合や別の場所から実行すると機能しなくなる場合があります。正規表現を引用符で囲めば問題は解決します。

それからコマンドは量指定子としてgrep扱います*

他の回答は、例えばセルギイ・コロディアジニーそしてコス--また、この質問のこの側面に、多少異なる方法で対処しています。そのため、まだ読んでいない方は、この回答の残りの部分を読む前または読んだ後に、ぜひ読んでみてください。

*がgrepに通ると仮定すると(引用符で囲めば確実) grep、それは次のことを意味すると解釈されます。先行する項目何度でも発生する可能性がある正確に一度だけ発生するのではなく一度だけ発生することもあります。あるいは、まったく発生しないこともあります。あるいは、繰り返されることもあります。どれでもそれらの可能性が一致します。

「アイテム」とはどういう意味ですか?

  • 独身者キャラクターbはリテラル に一致するためbb*は 0 個以上の に一致し、、、などbab*c一致します。acabcabbcabbbc

    同様に、.任意の文字に一致.*0文字以上の文字に一致します1したがって、、、、さらにはなどにa.*c一致します。acakcahjglhdfjkdlgjdfkshlgcacccccchjckhccまたは

  • 文字クラスはまたは に[xy]一致するため、または のいずれかである 0 個以上の文字に一致し、、、、、、、、などに一致します。xy[xy]*xyp[xy]*qpqpxqpyqpxxqpxyqpyxqpyyqpxxxqpxxyq

    これは、速記形式\w、、、など\Wの文字クラス。は任意の単語文字に一致するため、は 0 個以上の単語文字に一致します。\s\S\w\w*または

  • グループ\(bar\)は に一致するためbar\(bar\)*0 個以上の に一致しbar、、、などにfoo\(bar\)*baz一致します。foobazfoobarbazfoobarbarbazfoobarbarbarbaz

    -Eまたはオプションを使用すると-Pgrep正規表現をエレまたはペクレそれぞれではなく、ブレ( )の場合、グループはの代わりに で囲まれるため、の代わりに を、の代わりに\( \)を使用します。(bar)\(bar\)foo(bar)bazfoo\(bar\)baz

man grepgrep最後にはBREとEREの構文についてかなり分かりやすく説明されており、冒頭には受け入れ可能なコマンドラインオプションがすべてリストされています。このマニュアルページをリソースとしてお勧めします。また、GNU Grep ドキュメントそしてこのチュートリアル/リファレンスサイト(これについては、上記でいくつかのページにリンクしています)。

テストと学習にはgrep、パターンのみでファイル名なしで呼び出すことをお勧めします。次に、端末から入力を受け取ります。行を入力します。パターンに一致したテキストを含む行がエコーバックされます。終了するには、行の先頭でCtrl+を押します。これは入力の終了を知らせます。(または、ほとんどのコマンドライン プログラムと同様に+Dを押すこともできます。) 例:CtrlC

grep 'This.*String'

フラグを使用すると--colorgrep特定の部品正規表現に一致した行のリストが表示されます。これは、正規表現が何を行うかを把握する場合と、確認した後に探しているものを見つける場合の両方で非常に役立ちます。デフォルトでは、Ubuntu ユーザーに Bash エイリアスがあり、コマンド ラインからgrep --color=auto実行すると、この目的にはこれで十分です。grepそのため、手動で渡す必要さえない可能性があります--color

1 したがって、.*正規表現では、*シェルのグロブでの意味と同じ意味になります。ただし、違いは、grep一致した行を自動的に印刷することです。どこでも.*正規表現には含まれていないため、通常は正規表現の先頭または末尾に置く必要はありません。

関連情報