web-dev-qa-db-ja.com

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

から lsof出力でpid列とpathname列のみを抽出するにはどうすればよいですか?

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
    }
}}'

正規表現"\.pdf"は、gawkでは/.../pdf.../...と一致しますが、mawkでは一致しません。なんでかしら?

ありがとう。

7
Tim

正規表現ではなく、二重引用符で囲まれた文字列の処理方法についてだと思います。 Cスタイルのエスケープ(\nなど)はawk文字列で解釈され、gawkとmawkは無効なエスケープを異なる方法で処理します。

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

つまり、mawkはバックスラッシュをそのまま残しているようですが、gawkはバックスラッシュを削除します(少なくとも私のバージョンでは不平を言います)。したがって、使用される実際の正規表現はdifferentです。gawkでは、正規表現は.pdfです。これはもちろん/pdfに一致します。ドットは任意の1文字に一致するため、 mawkでの正規表現は\.pdfです。ドットはエスケープされ、文字どおり一致します。

GNU awkのマニュアルで明示的に言及 バックスラッシュエスケープシーケンスが定義されていない文字の前にバックスラッシュを使用することはできません(「通常の文字の前のバックスラッシュ」ボックスを参照してください):

以前にリストされた文字の1つではない何かの前の文字列定数にバックスラッシュを置くと、POSIX awkは意図的に発生したことを未定義のままにします。 2つの選択肢があります。

バックスラッシュを取り除きます
これは、BWK awkとgawkの両方が行うことです。たとえば、"a\qc""aqc"と同じです。
バックスラッシュはそのままにします
他のいくつかのawk実装がこれを行います。このような実装では、"a\qc"と入力することは、"a\\qc"と入力することと同じです。

ドットを正規表現でエスケープしたいと思うので、安全な方法は$NF ~ "\\.pdf"または$NF ~ /\.pdf/です(正規表現リテラル/.../があるため、エスケープは "double"ではありません処理済み」)。

POSIXテキスト は、エスケープの二重処理にも注意します。

右側のオペランド[of ~または!~]が字句トークン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
12
ilkkachu

テーブル here からわかるように、awkの正規表現では、バックスラッシュの後に最大3桁の8進数字、別のバックスラッシュ、または["/abfnrtv]は未定義です。

あなたの最善の策は、[.] の代わりに \.リテラルが必要な場合.

この場合、一般的な方法ではないのはmawkの動作であることに注意してください。一方、私が知っているすべてのawkの実装では、エスケープできます\.\+\*正規表現リテラル(/foo\.bar/)、mawkのみが正規表現($0~"foo\.bar")。

5
mosvy

ジョブに適したツールを使用します。次の2つの式があります。

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

ただし、どちらの場合も、パターンはリテラル文字列です。したがって、正規表現マッチングに悩まされる理由はなく、リテラル文字列マッチングを使用するだけです。

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

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

3
user327359

他の多くの言語と同様に\xは、文字列または正規表現では異なる意味を持っています。どちらでも使えます

$NF ~ /\.pdf/

または

$NF ~ "\\.pdf"

文字列"\.pdf"は、奇妙な言い方です".pdf"

2
JJoao