Grep:アスタリスク(*)は常に機能するとは限りません


11

以下を含むドキュメントをgrepした場合:

ThisExampleString

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

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

アスタリスクは不明な文字をいくつも示していると思いましたか?それが式の最初にある場合にのみ機能するのはなぜですか?これが意図された動作である場合、式の代わりに何を使用This*String*Stringますか?


それは正規表現がどのように機能するかではないためです...(特に:* != any number of unknown characters。ドキュメントを読んでください)
njzk2

回答:


18

正規表現のアスタリスクは、「直前の要素に0回以上一致する」ことを意味します。

あなたの特定のケースではgrep 'This*String' file.txt、あなたは「ねえ、grep、私に単語を一致させThi、その後にsゼロ回以上小文字を続け、その後に単語を続けてください」と述べようとしていますString。小文字sはどこにも見つからないためExample、grepは無視しThisExampleStringます。

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

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


6
バッシュ(およびUnixシェルのほとんど)では*特殊な文字であり、それが引用されたか、このような例のためにエスケープする必要がありますgrep 'This*String' file.txtか、この:grep This\*String file.txt予期しない結果に驚くことではないし。
pabouk

2
シェルでは@paboukは*ワイルドカードです。grepでは、*は正規表現演算子です。unix.stackexchange.com/q/57957/70524
muru

11
paboukは正しい、ファイル名の展開はコマンドが実行される前に行われます。比較strace grep .* file.txt |& head -n 1 strace grep '.*' file.txt |& head -n 1。また、実際にgrepは任意のUnicode文字(例:echo -ne ⇏ | grep ⇏出力)でも動作します
kos

1
@セルグ:あなたはここで高い評価を得ているので、私が何を言っているのかすぐに気づくと思いました。OPは質問bashにタグを付けたので、ここで説明するコマンドはによって解釈されると思いますbash。これは、最初にbashその特殊文字を解釈し、すべての拡張が実行された後にのみ、生成されたプロセスにパラメーターを渡すことを意味します。-----例えばbashで、このコマンドは:grep This.\*String file.txt出現します/bin/grep:これらのパラメータ0でgrep、1:This.*String2: file.txt。Bashがバックスラッシュを削除し、最初にエスケープ*されたものが文字通り渡されたことに注意してください。
pabouk

7
面白い(そしてかなり厄介なトラブルシューティング:)ことは、のようなコマンドgrep This.*String file.txtは通常動作することです。これは、おそらくシェルのワイルドカード式に一致するファイルがないためですThis.*String。このような場合、デフォルトではBashは文字列を含む引数を渡します*
pabouk

8

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

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

% 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-Pオプションを使用して)のPCREエンジンをオンにし、?メタキャラクターを追加できます。メタキャラクターは、*および+メタキャラクターの後に配置すると、貪欲度を変更する効果があります。

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

1:基本的な正規表現、拡張正規表現、およびPerl互換の正規表現


非常に有益な回答をありがとうございます。しかし、私は別の答えを選びました。それは、短くて理解しやすいからです。詳細を提供するための+1。
Trae

@Traeどういたしまして。それは結構です、多分これはあまりに複雑で、トピックにあまり詳しくない人にはあまりにも多くの仮定をしたことに同意します。
2015年

4

ここにあるリンクの説明の1つ:

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


1

*シェルのグロビング文字(「ワイルドカード」)と正規表現のメタ文字の両方に特別な意味があります。両方を考慮に入れる必要があります、正規表現を引用する場合は、シェルがそれを特別に処理することを防ぎ、変更せずにに渡すことができgrepます。概念的に似ていますが*、シェルにとっての意味は、シェルにとっての意味とはかなり異なりgrepます。

まずシェルが扱います*ワイルドカードとしてます。

あなたが言った:

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

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

引用符で囲まれ*ていない文字をシェルが検出すると、「ゼロ以上の任意の文字」を意味し、その文字を含む単語を、パターンに一致するファイル名のリストで置き換えます。(で始まるファイル名は除外されている-あなたのパターンがない限り、それ自体で始まる。あなたはとにかくそれらを含めるようにシェルを設定した)これはとして知られているグロブ -そしてまた、名によってファイル名展開パス名展開..

の効果grepは通常、最初に一致するファイル名が正規表現として解釈されます-正規表現ではないことが人間の読者には明らかであっても、他のすべてのファイル名はglobは、一致を検索するための内部のファイルと見なされます。(リストは表示されません。リストは不透明に渡されます。grep。ます。)これが発生することはほとんどありません。

これが時々問題にならない理由-そしてあなたの特定のケースでは、少なくとも今のところ問題はありません- 以下のすべてが当てはまる場合、それは*放置されます

  1. 名前が一致するファイルはありませんでした。 ...または、シェルでグロビングを無効にしました。通常、set -fまたは同等のものを使用しset -o noglobます。しかし、これは一般的ではなく、おそらくあなたがそれをしたことを知っているでしょう。

  2. *一致するファイル名がない場合、デフォルトの動作をそのままにするシェルを使用しています。これは、おそらく使用しているBashの場合ですが、すべてのBourneスタイルのシェルではそうではありません。(たとえば、人気のあるシェルZshのデフォルトの動作は、グロブが(a)展開するか、(b)エラーを生成するかのいずれかです。)または、シェルのこの動作を変更しました。シェル全体。

  3. 他の方法では、一致するファイルがない場合にグロブをも置き換えないようにすることも、この状況でエラーメッセージを表示して失敗することもシェルに伝えていません。Bash では、それぞれ、nullglobまたはfailglob シェルオプションを有効にすることで行われます

#2と#3に依存することもできますが、#1に依存することはほとんどありません。grep引用符で囲まれていないパターンで動作するコマンドは、ファイルが異なる場合や、別の場所から実行すると動作しなくなる場合があります。正規表現を引用すれば、問題はなくなります。

次にgrepコマンドは*数量詞として扱います。

他の回答-ものなどSergiy Kolodyazhnyyによるコスによって多少異なる方法で、この質問のこの局面--alsoアドレス、。ですから、まだ読んでいない人には、この回答の残りの部分を読む前または読んだ後に読むことをお勧めします。

*がそれをgrepに変換すると仮定します(これにより引用が確実になるはずです)grepその前にある項目が正確に1回発生する必要はなく、何度も発生する可能性があることを意味します。それでも一度は発生する可能性があります。または、まったく存在しない可能性があります。またはそれを繰り返すこともできます。これらの可能性のいずれかに適合するテキストが照合されます。

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

  • 単一の文字。以来b一致リテラルはbb*ゼロまたはそれ以上の一致b従って、Sをab*c一致acabcabbcabbbc、等

    同様に、任意の文字に一致するため..*ゼロ個以上の文字と一致する1ので、a.*cマッチacakcahjglhdfjkdlgjdfkshlgc、でもacccccchjckhcc、などまたは

  • 文字クラス。以降[xy]マッチxまたはy[xy]*それぞれがいずれかのあるマッチがゼロ個以上の文字x又はy、従ってp[xy]*q一致pqpxqpyqpxxqpxyqpyxqpyyqpxxxqpxxyq、など

    これはまたして適用されるフォーム速記のような文字クラスのを\w\W\s、と\S。は\w任意の単語文字に\w*一致するため、0個以上の単語文字に一致します。または

  • グループ。ため\(bar\)マッチbar\(bar\)*マッチは、ゼロまたはそれ以上barの、従ってfoo\(bar\)*baz一致foobazfoobarbazfoobarbarbazfoobarbarbarbaz、等

    -E-Pオプション、grepとしてあなたの正規表現として扱いEREPCREをむしろとしてよりも、それぞれBRE、その後、グループが囲まれている( )代わりに、\( \)ように、あなたが使用したい、(bar)代わりに\(bar\)foo(bar)bazの代わりにfoo\(bar\)baz

man grep最後に、BREとERE構文の合理的にアクセス可能な説明を示しgrep、最初に受け入れるすべてのコマンドラインオプションを一覧表示します。そのマニュアルページをリソースとしてお勧めします。また、GNU Grepのドキュメントこのチュートリアル/リファレンスサイト(上記のいくつかのページにリンクしています)もお勧めします。

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

grep 'This.*String'

--colorフラグを使用すると、grepと、正規表現に一致する行の特定の部分が強調表示されます。これは、正規表現の機能を理解するためと、一度行ったときに探しているものを見つけるための両方に非常に役立ちます。デフォルトでは、Ubuntuユーザーはコマンドラインからgrep --color=auto実行grepしたときに実行する(この目的には十分です)ようにするBashエイリアスを持っているため、--color手動で渡す必要すらありません。

1 したがって.*、正規表現では*、シェルグロブの意味を意味します。しかし、違いがあることであるgrep自動的にマッチ含む行を印刷しどこでもそれが持っている一般的に不要ですので、その中に.*正規表現の先頭や末尾。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.