\\を使用する正規表現と\を使用する正規表現


10

どして

grep e\\.g\\. <<< "this is an e.g. wow"

そして

grep e\.g\. <<< "this is an e.g. wow"

同じことをしますか?

3番目のスラッシュを追加すると、同じ結果になります。しかし、4番目のスラッシュを追加すると、機能しなくなります。これは、クラスの古い試験の質問に関係しています。2つのバックスラッシュのあるものは、「eg」で行を出力するために機能するかどうか尋ねましたが、最初は機能しないと思っていましたが、確認してみました。説明は何ですか?


私はbashが\\\.grep を取得して提供すると考え\.ていましたが、そうではありません。良い質問

回答:


9

最初に、単一のスラッシュは一致しすぎていることに注意してください。

$ echo $'eegg \n e.g.' | grep e\.g\.
eegg
 e.g.

限りバッシュが懸念され、エスケープ期間は、期間と同じです。Bashはその期間をgrepに渡します。grepの場合、ピリオドはすべてに一致します。

さて、考慮してください:

$ echo $'eegg \n e.g.' | grep e\\.g\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\.g\\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\\.g\\\\.
$

Bashがダブルスラッシュを検出すると、それをシングルスラッシュに減らし、それをgrepに渡します。grepは、上記の3つのテストの最初のテストで、ピリオドの前に単一のスラッシュを表示します。したがって、これは正しいことを行います。

トリプルスラッシュの場合、Bashは最初の2つを1つのスラッシュに減らします。その後、それを見\.ます。エスケープ期間はBashにとって特別な意味がないため、これはプレーン期間に短縮されます。その結果、grepは、必要に応じてピリオドの前にスラッシュを表示します。

4つのスラッシュを使用して、Bashは各ペアを1つのスラッシュに減らします。bashは、2つのスラッシュとピリオドをgrepに渡します。grepは2つのスラッシュとピリオドを認識し、2つのスラッシュを1つのリテラルスラッシュに減らします。入力に任意の文字が続くリテラルスラッシュがない限り、一致はありません。

最後に、単一引用符内ではすべての文字がリテラルであることを思い出してください。したがって、次の3つの入力行が与えられた場合、grepコマンドは、入力にリテラルスラッシュが含まれる行でのみ一致します。

$ echo 'eegg
e.g.
e\.g\.' |  grep e\\\\.g\\\\.
e\.g\.

Bashの動作の概要

Bashの場合、ルールは

  • 2つのスラッシュは1つのスラッシュに削減されます。

  • ピリオドのような通常の文字の前のスラッシュは、通常の文字(ピリオド)にすぎません。

したがって:

$ echo \. \\. \\\. \\\\.
. \. \. \\.

このすべての混乱を回避する簡単な方法があります。Bashコマンドラインでは、正規表現を単一引用符で囲む必要があります。単一引用符内では、Bashはすべてをそのままにします。

$ echo '\. \\. \\\. \\\\.'  # Note single-quotes
\. \\. \\\. \\\\.

質問:bashがバックスラッシュとして表示するには、2つのバックスラッシュが必要です(1つはエスケープシーケンスで、もう1つはリテラルバックスラッシュです)。それで、3がある場合、bashは3番目のストラグラーをエスケープシーケンスとしても扱いますか?何もエスケープしていないので、破棄されますか?
Franz Kafka

@DanielAmaya 3番目は、後続の文字のエスケープとして扱われます。私たちの場合、その文字はピリオドであり、bashの場合(grepとは異なり)、エスケープされたピリオドは単なるプレーンピリオドです。その後、bashはプレーン期間をgrepに渡します。
John1024 2014年

@DanielAmaya echoこれらのケースでbashが何をするかを説明するステートメントについては、更新された回答を参照してください。
John1024 2014年

2
@DanielAmayaどちらの場合も、bashは最初の2つのスラッシュを1つのスラッシュに減らします。何が残っています\..。bashの場合、これらは両方とも同じです。これらは通常のピリオドと同等です。したがって、全体として、bashがgrepに提供するものはどちらも同じです。つまり、単一のスラッシュとそれに続くピリオドです。
John1024 2014年

1
ほんの少しの追加- echoこのプログラムの多くの実装のため、使用は正規表現をテストするための非常に信頼できる方法ではありません。たとえば、私のzsh(組み込みのエコー)では、が返されますecho \. \\. \\\. \\\\. \\\\\.. \. \. \. \.、が/bin/echo \. \\. \\\. \\\\. \\\\\.返されます. \. \. \\. \\.。のようなものprintf "%s" ...がおそらくより良い方法です。
jimmij 2014年

4

出力は文字列に対してのみ同じですが、一般的にこれらの正規表現は異なることを行います。2番目のパターンe,g,(コンマ付き)、3番目e\.g\.(ドット)、4番目e\,g\,(コマ)、および-ogrepにオプションを追加して、例を少し変更して、一致した部分のみを印刷します。

  • 次の場合は、.任意の文字に一致します(通知''e.g.、後で説明します)。

    $ grep -o 'e.g.' <<< grep -o 'e.g.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
    e,g,
  • 次に.、バックスラッシュ\でエスケープするので、リテラルのみ.が一致します。

    $ grep -o 'e\.g\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
  • しかし\、別\のでエスケープすることができるので、リテラル\.(つまり任意の文字)が後に続くように一致します。

    $ grep -o 'e\\.g\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.
    e\,g\,
  • しかし、一致させたく\.ない\,場合\は、ドットの特別な意味をエスケープするためにさらに別のものが必要です。

    $ grep -o 'e\\\.g\\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.

ここで、''grep引数を使用しなかったため、バックスラッシュをシェルの解釈からエスケープするために、別のバックスラッシュを追加する必要があります。

grep 'e\.g\.'     => grep e\\.g\\.
grep 'e\\.g\\.'   => grep e\\\\.g\\\\.  (each backslash has to be quoted separately)
grep 'e\\\.g\\\.' => grep e\\\\\\.g\\\\\\. (3 x 2 = 6 backslashes in total)

3

を実行するgrep e\.g\.と、シェルはバックスラッシュを消費するためgrep e.g.、一致するを実行しています。を実行するgrep e\\.g\\.と、シェルは再びスラッシュを消費し、今はgrep e\.\g.再び一致するを実行しています。これで、シェルへのバックスラッシュはのようになり\\ます。したがって、がある場合\\、最初のエスケープシーケンスはエスケープシーケンスで、2番目はリテラルのバックスラッシュです。あなたが行うとgrep e\\\.g\\\.、それはまだされて終わるgrep e\.\g.エスケープシーケンス(存在しないので、\最初の前に)\それリテラルにします\。このように、バックスラッシュは\を覚えておいてくださいgrep e\\\\.\\\\gされて終わるgrep e\\.g\\.明らかに一致しません、。

シェルが何をしているかを確認するには、echoを使用します(例:echo grep e\\.g\\. <<< "this is an e.g. wow"vs. echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"


0

2つのコマンドは、入力に対してのみ同じ出力を生成しますが、それ以外は異なります。何が起こっているのかを理解するために、パラメータが最初にbash、次にによってどのように解釈されるかを知る必要がありますgrep

バッシュでの脱出

\\自身を含む後続の文字の特別な意味を取り消す特殊文字です。次の文字に特別な意味がない場合は、そのまま渡されます。コマンドと結果の例:

  • echo \aa—エスケープされた通常の文字は文字を与える
  • echo \\\—エスケープされた特殊文字は文字を与える
  • echo \\\a\a—特別な組み合わせ、普通
  • echo \\\\\\—スペシャルの組み合わせ、スペシャル

echo結果の文字列をbash解釈してから出力します。詳細:bashドキュメントbashハッカーwikiPOSIX仕様

.では、特別な意味はありませんbash。シェルの普通のキャラクターです。以下は、例に関連するシーケンスです。

  • echo ..
  • echo \..
  • echo \\.\.
  • echo \\\.\.
  • echo \\\\.\\.

bashのリテラル文字列のより簡単なソリューション

文字通りパラメータを渡すにbashは、一重引用符の'エスケープを使用できます。一重引用符の間では、一重引用符だけが特別な意味を持つ文字であるため、文字の特別な意味を気にする必要はありません。文字列の最初の部分を囲んだ後、一重引用符を挿入できます。例
echo 'part1'\''part2':: part1'part2

grepの正規表現

\と同様の意味を持つエスケープ文字bashです。任意の文字の1つの出現.表す特殊文字です。参照:POSIX regexGNU grep regex。正規表現の例:

  • .aまたはなどの任意の文字に一致します.
  • \..文字通りのみに一致

あなたの例

以下のすべての例の2行目には、'どのリテラル文字列がに渡されるかbashを示す単一引用符付きの同等のものがありますgrep。次に、grepがエスケープを実行した後、例で唯一可能な特殊文字は、.任意の文字と一致します。3行目には、式が一致する内容の説明があります。

  • grep e.g. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    e任意の文字g任意の文字 - 一致e.g.およびおそらく他の弦のようにeagb
  • grep e\.g\. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    e任意の文字g任意の文字 - 一致e.g.およびおそらく他の弦のようにexgy
  • grep e\\.g\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.文字通り— 一致e.g.のみ
  • grep e\\\.g\\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.文字通り— 一致e.g.のみ
  • grep e\\\\.g\\\\. <<< "this is an e.g. wow"
    grep 'e\\.g\\.' <<< "this is an e.g. wow"
    e\任意の文字g\任意の文字一致しませんe.g.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.