web-dev-qa-db-ja.com

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

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

ThisExampleString

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

式が引用符で囲まれているかどうかは違いません。

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

8
Trae

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

grep 'This*String' file.txtを使用した特定のケースでは、「ちょっと、grep、Word Thiに一致し、その後に小文字のsが0回以上続き、その後にWord Stringが続きます」と言います。小文字のsExampleのどこにも見つからないため、grepはThisExampleStringを無視します。

grep '*String' file.txtの場合、「grep、空の文字列に一致する-文字通り何もない-Word Stringの前に」と言っています。もちろん、それはThisExampleStringの読み取り方法ではありません。 ( 他の考えられる意味 ---Eフラグを使用して、または使用せずにこれを試すことができます-しかし、ここで本当に必要なものはありません。)

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

15

BREの*メタキャラクター1s、ERE1sおよびPCRE1sは、以前にグループ化されたパターンの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互換の正規表現

8
kos

ここにある説明の1つ link

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

4
Ova

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

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

あなたが言った:

式を引用符で囲んでも違いはありません。

これは、コマンドを実行したときにたまたまディレクトリにあるファイルによって異なります。ディレクトリセパレーター/を含むパターンの場合、システム全体に存在するファイルに依存する場合があります。常に quotegrep-の正規表現と single quotes が通常最良である必要があります-unlessで大丈夫です 9種類の潜在的に驚くべき変換 シェルは、grepコマンドを実行する前にbeforeを実行します。

シェルが 引用符付き ではない*文字を検出すると、「任意の文字の0個以上」を意味するとみなされ、 それを含むWordを置き換えます のリストに置き換えますパターンに一致するファイル名。 (.で始まるファイル名は除外されます-パターン自体が.またはで始まる場合を除き、いずれにせよそれらを含めるようにシェルを設定しました。)これは globbing -また、名前filename expansionおよびpathname expansionによっても。

grepを使用すると、通常、最初の一致するファイル名が正規表現として使用されます。たとえそれがnotが正規表現であることは人間の読者には明らかです。 -一方、グロブから自動的にリストされた他のすべてのファイル名は、一致を検索するファイルinsideとして取得されます。 (リストは表示されません。grepに不透明に渡されます。)これが起こることはほとんどありません。

これが問題ではないsometimesである理由-そしてあなたの特定のケースでは、少なくともこれまでのところではなかった-それは*次のすべてに該当する場合

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

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

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

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

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

他の答え- Sergiy Kolodyazhnyyによる および kosによる -なども、この質問のこの側面に多少異なる方法で対処しています。したがって、この回答の残りの部分を読む前または読んだ後に、まだ読んでいない人にそうすることを勧めます。

*がgrepになったと仮定します-その引用符で確認する必要があります--grepは、その前の項目 何度でも発生する可能性があります ではなく、一度だけ発生する。まだ一度発生する可能性があります。または、まったく存在しない可能性があります。または、繰り返すことができます。これらの可能性のanyに適合するテキストが一致します。

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

  • 単一の 文字bはリテラルbと一致するため、b*はゼロ個以上のbsと一致します。したがって、ab*cacabcabbcabbbcなどと一致します。

    同様に、 .は任意の文字と一致します なので、.*はゼロ個以上の文字と一致します1、したがってa.*cacakcahjglhdfjkdlgjdfkshlgc、さらにはacccccchjckhccなどに一致しますOr

  • 文字クラス[xy]は、それぞれがx又はy、従って[xy]*マッチxypqpxqpyqpxxqpxyqpyxqpyyq、等のいずれかであるゼロ以上の文字にマッチするp[xy]*qpxxxq又はpxxyqを一致するため.

    これは、\w\W\s\Sなどの文字クラスの 短縮形 にも適用されます。 \wはすべてのWord文字と一致するため、\w*は0個以上のWord文字と一致します。 または

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

    -Eまたは-Pオプションを使用すると、grepは正規表現を BRE ではなく、それぞれ ERE または PCRE として扱います=、そしてグループは()ではなく\(\)で囲まれているため、\(bar\)の代わりにfoo(bar)bazfoo\(bar\)bazの代わりに(bar)を使用します。

man grep は、最後にBREおよびERE構文のわかりやすい説明を提供し、先頭にgrepが受け入れるすべてのコマンドラインオプションをリストします。リソースとしてそのマニュアルページをお勧めします。また、 GNU Grepドキュメンテーション および このチュートリアル/リファレンスサイト (番号にリンクしています)上のページの)。

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

grep 'This.*String'

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

1したがって、正規表現の.*は、シェルグロブの*の意味を意味します。ただし、grepは、一致anywhereを含む行を自動的に出力するため、正規表現の先頭または末尾に.*を含める必要はありません。

1
Eliah Kagan