grepパターンでスペースを処理する正しい方法

grepパターンでスペースを処理する正しい方法

最新グレブ 3.8バックスラッシュでエスケープされたスペースを含むパターンについて警告する

$ grep "bla\ bazz" t 
/tmp/bin/grep: warning: stray \ before white space
...

そしてgrep 3.6は文句を言わない。このパターンを処理する正しい方法は何ですか?ただスペースから脱出しないでください?つまり

$ grep "bla bazz" t

grepエスケープされていないスペースを誤って処理するために、よりエキゾチックなものがありますか?たぶん、すべてをきちんと整理するために別のクォータを使用しますか?

答え1

空白文字は正規表現では特別ではないので(perlこのフラグが有効な -like 式を除くx)、エスケープしてはいけません。\空白に従うと、POSIX正規表現で指定されていない結果が生成されます。

だからあなたは以下が欲しい:

grep 'blah bazz'

より明確にしたい場合は、次のものを使用できます。

grep 'blah[ ]bazz'

\より一般的には正規表現演算子ではない文字の前にisを入れてはいけません。X正規表現演算子ではありませんが、今\Xではなくても将来のバージョンにいる可能性が高いです。たとえば、、+はデフォルト<d正規表現演算子ではありませんが、一部の実装では、および\<\+使用\dされますgrep

\次の場合は、末尾のスペースを使用する必要があります。

grep -P '(?x)  foo \  bar'
perl -ne 'print if / foo \  bar /x'

foo barxフラグがオンのときに一致が発生します。しかし、それでもあなたはこれをしたいです:

grep -P '(?x)  foo [ ] bar'

より読みやすくするため。このフラグの全体的な目的は、x正規表現をより明確にすることです。たとえば、次のようになります。

perl -ne 'print if m{
  \d{4}   # year
  - \d{2} # month
  - \d{2} # day
  [ ] (foo | bar | baz)}x'

そして

perl -ne'print if/\d{4}-\d{2}-\d{2} (foo|bar|baz)/'

ただし、角括弧式内のスペースも無視されるフラグ(PCREではなくPerl 5.26+では)[ ]と一緒に使用することはできません。xx

perldoc perlrePerl正規表現とman pcrepatternPCRE(Perl互換正規表現)の詳細については、参考資料を参照してください。使用する\Q \Eことは別のオプションです。

とにかく、空白はシェル構文では特殊文字ですが、正規表現では特殊文字ではありません*\、したがって、両方のifは次のようになります。文字通り一致することを意味し、好ましくはシェルの周りの引用符で囲み(またはPerlのような場合には)正規表現を表現します。()?$^[]\[...]\Q...\E

\$正規表現で一般的であり、これらの文字は依然として二重引用符内のシェルに特別であるため、正規表現を二重引用符ではなく一重引用符で囲むことをお勧めします。シェルパラメータを正規表現に拡張する必要がある場合、または正規表現にaを含める必要があるgrep "^$var"場合にのみ、二重引用符を使用してください。'

正規表現と反対のリテラル文字列grep、つまりエスケープされた文字列です。すべて正規表現演算子の場合-FF固定文字列用)オプションを使用できますgrep。たとえば、

grep -F 'blah\ bazz'

含まれている項目を見つけますblah\ bazz

答え2

シェルからスペースを保護するためにスペースをエスケープするだけですgrep。空白文字は正規表現には特別ではなく、シェルで引数を定義するために使用される文字なので、シェルでのみ特殊です。したがって、パターンが引用されていない場合(悪い考え)、スペースが必要です。

$ echo 'foo bar' | grep -c foo\ bar
1

これにより、シェルはファイル名にfoo bar渡された2つの引数を解析しません。以下を使用してこれを確認できます。bargrepset -x

$ set -x
$ echo 'foo bar' | grep -c foo\ bar
+ grep -c 'foo bar'
+ echo 'foo bar'
1

脱出できない場合は、次のようになります。

$ echo 'foo bar' | grep -c foo bar
+ grep -c foo bar
+ echo 'foo bar'
grep: bar: No such file or directory

ただし、パターンを引用するとシェルからパターンが保護され、エスケープは必要ありません。

$ echo 'foo bar' | grep -c "foo bar"
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1

または

$ echo 'foo bar' | grep -c 'foo bar'
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1

そのため、空白の前にリテラル(引用符)が表示されgrepたら警告します。\\脱出するアイテムがないので\意味がないので、ちょうど(space)になったと警告します。 「エスケープ可能」でない場合は、エスケープされた他の文字に対して同じことを行います。

$ echo 'foo bar' | grep -c "f\oo\ bar"
+ grep --color -c 'f\oo\ bar'
+ echo 'foo bar'
grep: warning: stray \ before o
grep: warning: stray \ before white space
1

答え3

3.8リリースノートから始めます(https://savannah.gnu.org/news/?id=10191):

散乱バックスラッシュを持つ正規表現は、
未指定の動作によって予期しない結果が発生する可能性があるため、警告を発します。たとえば、 '\a' と 'a' は必ずしも同じではありません。
https://bugs.gnu.org/39678。同様に、
反復演算子で始まる正規表現やサブ式も指定
されていない動作によって警告を発します。たとえば、* a(+ b | {1} c)には
3つの警告理由があります。これらの警告は
一時的なサポートのためのものです。今後のリリースではバグが発生する可能性があります。

関連情報