webdevqa.jp.net

Grepは、私が期待するファイル内のすべての一致を見つけることができないようです

grepを完全に理解していないのか、正規表現が問題の原因であるのかわからないので、2つの質問があります。 test.txtという名前の簡単なテストファイルがあります。内容は次のとおりです。

$ cat test.txt Settings.xml blah Settings_1.xml blah Settings_2.xml

次のコマンドを使用して、上記のテストファイルのみを含むディレクトリでgrepを実行すると、一致するものが返されません。

$ grep -ir "Settings*xml"

1)ワイルドカード*がピリオドをキャッチしないのはなぜですか?

そして、grepをそのように実行すると:

$ grep -ir "Settings*.xml"

唯一の違いはワイルドカードの後のピリオドであり、結果は次のとおりです。

test.txt:Settings.xml

2)grepが他の2つの一致を見つけられないのはなぜですか?

2
Ben Sandeen

その理由は、*は正規表現の特殊文字であり、zero or more preceding charactersを意味するためです。 *をエスケープして、*を含むリテラル\文字を意味する必要があります。だからあなたの例では:

grep -ir "Settings*xml"

Settingで始まり、0個以上のs文字と最後にxmlがある文字列を検索します。 xmlの前には常に.が付いているため、ファイルにはそのような文字列はありません。この:

grep -ir "Settings*.xml"

Settingで始まり、0個以上のs.xmlが0個以上のs文字の後にある文字列を検索します。

最初の正規表現は次のようなものに一致します。

Settingssxml

3

この他の答え 何が起こったのかを説明し、あなたの明確な質問に答えます。私の答えは、より広い文脈を紹介することを目的としています。

*は0文字以上(任意の文字)に一致し、.は文字通り.を意味すると予想したと思います。これはシェルグロブで機能します。つまり、次のようなファイルがある場合です。

$ ls -1
Settings.xml
blah
Settings_1.xml
Settings_2.xml

次に(たとえば、bashで)次のことができます。

$ echo Settings*.xml
Settings.xml Settings_1.xml Settings_2.xml

grepが正規表現構文を使用しているため、期待したものが得られませんでした。

  • .は(ほぼ)すべての文字に一致します。
  • *は、「0個以上の先行文字」を意味します。
  • \は、次の文字を文字どおりに解釈するように強制します。

そのため、"Settings*.xml"の代わりに"Settings.*\.xml"を使用する必要がありました。この場合:

  • .*は、*が行うと思ったことを実行します。
  • \.は、.が行うと思っていたことを実行します。
3