web-dev-qa-db-ja.com

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

どして

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

そして

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

同じことをしますか?

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

10
Wyatt Grant

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

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

Bash に関する限り、エスケープされたピリオドはピリオドと同じです。 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つのliteralスラッシュに減らします。入力に任意の文字が続くリテラルスラッシュがない限り、一致はありません。

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

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

Bashの動作の概要

バッシュの場合、ルールは

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

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

したがって:

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

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

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

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

  • 次の場合、.は任意の文字に一致します(''の周りの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)
4
jimmij

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

シェルが実行していることをシェルがどのように認識しているかを確認するには、echoを使用します(例:echo grep e\\.g\\. <<< "this is an e.g. wow"echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"

3
Franz Kafka

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

バッシュでの脱出

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

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

echoは、bashが解釈した結果の文字列を出力します。詳細: bashのドキュメントbash hackers 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.
0
pabouk