web-dev-qa-db-ja.com

-regexが改行と一致しないのはなぜですか?

なぜこれが失敗するのですか?

touch "$(printf "a\nb")"; find . -regex './.\n.'

私もこれらを試しましたが、どれもうまくいきませんでした:

find . -regextype posix-extended -regex '.\n.'
find . -regextype posix-awk -regex '.\n.'
find . -regextype posix-basic -regex '.\n.'
find . -regextype posix-egrep -regex '.\n.'

それが動作しているように見える唯一の方法は(ありがとう@MichaelMrozek)です

find . -regex './.'$'\n''.'

これは控えめに言っても面倒です。では、なぜfindの正規表現は\nを処理できないように見えるのですか?


これまでの回答に応じて更新:

はい、\nはEREの一部ではなく、それは私の誤解の1つでしたが、findposix-awkおよびgawkmawk予想どおり\nに一致:

$ printf "f1l1\nhas newline:f2l1#f1l2 does not:f2l2#" | 
    mawk -F: 'BEGIN{RS="#"}; ($1~/\n/){print $1}' 
f1l1
has newline

テストする純粋なawkがないので、おそらくPOSIX awkは一致しませんか?そうでない場合、findは実際にposix-awk正規表現を実装していませんか?

8
terdon

GNU findはエスケープシーケンスとして\nをサポートしていません。正規表現\nは、文字nと一致します。GNU findは従来のEmacs構文をコピーしますが、この機能もありません¹。

GNU findは他の正規表現構文をサポートしていますが、制御文字を表すバックスラッシュ文字またはバックスラッシュ8進数はサポートしていません。引数に文字どおり制御文字を含める必要があります。

さまざまな正規表現構文があります。 POSIX 基本正規表現 (BRE)も 拡張正規表現 (ERE)も、\nまたはバックスラッシュ8進エスケープを含みません。どちらの定義も、特殊文字が定義されていない場合、バックスラッシュの意味を残します。ユーティリティ awk および sed はどちらも、改行を意味する\nをサポートしています。これは、これらのユーティリティに固有です(一般的なものですが、普遍的ではないことがわかります)。

シェルスクリプトから、あなたは書くことができます

find . -regex $'./.\n.'     # ksh/bash/zsh only
find . -regex './.
.'
find . -name '*
*'

¹ まったく論理的に:インタラクティブに使用する場合は、C-qで任意の文字を入力できます。プログラミングで使用する場合、\nは文字列リテラル構文の一部として存在します。

改行は'\ n'と一致することはできません。正規表現では特別な意味がないためです(たとえば改行)。ただし、行末と一致することはできます。 = $正規表現を使用します。

6
babasbot

標準Cライブラリではfindfnmatchfunctionを使用しているため、_FNM_NOESCAPE_が設定されていない場合、パターンのバックスラッシュ文字の後に他の文字が続くと、文字列の2番目の文字と一致します。

_FNM_NOESCAPE

Don't treat the `\' character specially in patterns. Normally, `\' quotes
the following character, turning off its special meaning (if any) so that it 
matches only itself. When quoting is enabled, the pattern `\?' matches only 
the string `?', because the question mark in the pattern acts like an 
ordinary character. If you use FNM_NOESCAPE, then `\' is an ordinary character.
_

find (GNU findutils) 4.4.2と_glibc 2.15_で確認すると、このオプションはオフになっています。 _line 42_の_fnmatch.h_を確認します。

_#define FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
_
1
cuonglm