正規表現 ``\.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

おすすめ記事