正規表現 ``\.pdf'`がgawkでは `/.../pdf.../...`と一致しますが、mawkでは一致しないのはなぜですか?

正規表現 ``\.pdf'`がgawkでは `/.../pdf.../...`と一致しますが、mawkでは一致しないのはなぜですか?

~からlsof出力からpid列とパス名列のみを抽出する方法は?

awk '{ for (i=9; i<=NF; i++) {
    if ($i ~ "string" && $1 != "wineserv" && $5 == "REG" && $NF ~ "\.pdf") {
        $1=$2=$3=$4=$5=$6=$7=$8=""
        print
    }
}}'

正規表現は gawk では"\.pdf"一致します/.../pdf.../...が、mawk では一致しません。理由を知りたいです。

ありがとうございます。

答え1

私はこれが正規表現とは関係ありませんが、二重引用符で囲まれた文字列を処理する方法だと思います。 Cスタイルのエスケープ(例\n:)はawk文字列として解釈され、gawkとmawkは無効なエスケープを異なる方法で処理します。

$ mawk 'BEGIN { print "\."; }'
\.
$ gawk 'BEGIN { print "\."; }'
gawk: cmd. line:1: warning: escape sequence `\.' treated as plain `.'
. 

つまり、mawkはバックスラッシュをそのままにしているようですが、gawkはバックスラッシュを削除します(少なくとも私のバージョンでは文句を言います)。したがって、実際に使用される正規表現は次のようになります。その他:gawkの正規表現はです。ドットはすべての単一文字と一致するため、当然と一致します。一方、mawk では正規表現は です。.pdfここで、ドットはエスケープされ、文字通り一致します。/pdf\.pdf

GNU awkのマニュアルには明示的に言及されています。定義されたバックスラッシュエスケープシーケンスを持たない文字の前にバックスラッシュを使用することは移植できません(「一般文字の前のバックスラッシュ」ボックスを参照)。

POSIX awk は、前にリストされた文字の 1 つではなく、文字列定数の文字の前にバックスラッシュを置くと、何が起こるかを意図的に未定義のままにします。 2つのオプションがあります。

バックスラッシュの削除
これがBWK awkとgawkがすることです。例えば。"a\qc""aqc"
バックスラッシュを維持
他のawk実装はこれを行います。この実装では、入力は入力"a\qc"と同じです"a\\qc"

正規表現で点をエスケープしようとしているので、安全な方法はまたは$NF ~ "\\.pdf"です$NF ~ /\.pdf/(正規表現リテラルを使用すると、/.../エスケープが「二重処理」ではないため)。

これPOSIX テキストまた、エスケープ処理の二重処理に注意してください。

正しいオペランドの場合[~または!~]上記のエスケープ規則を含む文字列値が拡張正規表現として解釈される語彙トークンERE以外の式。気づくこれと同じエスケープ規則は、文字列リテラルの値を決定するためにも適用されます。(語彙トークンSTRING)文字列リテラルを使用するときに再適用する必要があるこの文脈で。

したがって、これはgawkとmawkの両方で機能します。

$ ( echo .pdf; echo /pdf ) |
  awk '{ if ($0 ~ "\\.pdf") print "   match: " $0; else print "no match: " $0; }'
   match: .pdf
no match: /pdf

このように:

$ ( echo .pdf; echo /pdf ) |
  awk '{ if ($0 ~ /\.pdf/) print "   match: " $0; else print "no match: " $0; }'
   match: .pdf
no match: /pdf

答え2

テーブルで見ることができます。ここ、awkの正規表現では、バックスラッシュの後に最大3つの8進数がない、別のバックスラッシュ、または未定義の["/abfnrtv]バックスラッシュがあります。

最善の方法は、テキストが必要な場合は[.]代わりに文章を書くことです。\..

この場合の動作はmawk一般的な規則に従わない。awk私が知っているすべての実装では、正規表現リテラル()で文字をエスケープできますが、正規表現として使用されている場合にのみ文字をエスケープできます。同じ操作が行われます\.\+文字列()から。\*/foo\.bar/mawk$0~"foo\.bar"

答え3

作業に適したツールを使用してください。次の2つの表現があります。

$i ~ "string"
$NF ~ "\.pdf"

ただし、どちらの場合も、パターンはリテラル文字列です。したがって、正規表現のマッチングを使用することを気にする理由はありません。ただリテラル文字列の一致を使用してください。

index($i, "string")
index($NF, ".pdf")

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html#tag_20_06_13_13

答え4

他の多くの言語と同様に、\x文字列や正規表現でも異なる意味を持ちます。あなたはそれを使用することができます

$NF ~ /\.pdf/

または

$NF ~ "\\.pdf"

文字列は"\.pdf"表現する奇妙な方法です。".pdf"

関連情報