Warum stimmt der reguläre Ausdruck "\ .pdf" mit "/ ... / pdf ... / ..." in gawk überein, aber nicht in mawk?

Antworten:

12

Ich denke nicht, dass es um den regulären Ausdruck geht, sondern darum, wie mit der Zeichenfolge in doppelten Anführungszeichen umgegangen wird. C-artige Escapezeichen (wie \n) werden in awk-Zeichenfolgen interpretiert, und gawk und mawk behandeln ungültige Escapezeichen unterschiedlich:

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

Das heißt, mawk scheint den Backslash unverändert zu lassen, während gawk ihn entfernt (und sich zumindest in meiner Version beschwert). Die tatsächlich verwendeten regulären Ausdrücke sind also unterschiedlich : In gawk ist der reguläre Ausdruck .pdf, der natürlich übereinstimmt /pdf, da der Punkt mit einem einzelnen Zeichen übereinstimmt, während in mawk Ihr regulärer Ausdruck ist \.pdf, in dem der Punkt maskiert und buchstäblich abgeglichen wird.

Im Handbuch von GNU awk wird ausdrücklich erwähnt, dass es nicht portabel ist, einen Backslash vor einem Zeichen ohne definierte Backslash-Escape-Sequenz zu verwenden (siehe Kasten "Backslash vor regulären Zeichen"):

Wenn Sie einen Backslash in eine Zeichenfolgenkonstante vor etwas einfügen, das nicht zu den zuvor aufgeführten Zeichen gehört, lässt POSIX awk das, was passiert, absichtlich undefiniert. Es gibt zwei Möglichkeiten:

Den Backslash ausziehen
Dies ist, was BWK awk und gawk beide tun. Zum Beispiel "a\qc"ist das gleiche wie "aqc".
Lassen Sie den Backslash in Ruhe
Einige andere awk-Implementierungen tun dies. In solchen Implementierungen ist das Tippen "a\qc"dasselbe wie das Tippen "a\\qc".

Ich gehe davon aus, dass Sie möchten, dass der Punkt in der Regex maskiert wird, also sind die sicheren Wege entweder $NF ~ "\\.pdf"oder $NF ~ /\.pdf/(da mit dem Regex-Literal die Escape-Zeichen /.../nicht "doppelt verarbeitet" werden).

Der POSIX-Text weist auch auf die doppelte Verarbeitung der Escapezeichen hin:

Wenn der rechte Operand [von ~oder !~] ein anderer Ausdruck als das lexikalische Token ERE ist, wird der Zeichenfolgenwert des Ausdrucks als erweiterter regulärer Ausdruck interpretiert, einschließlich der oben beschriebenen Escape-Konventionen. Beachten Sie, dass dieselben Escape-Konventionen auch bei der Bestimmung des Werts eines Zeichenfolgenliterals (des lexikalischen Token STRING) angewendet werden müssen und daher ein zweites Mal angewendet werden müssen, wenn in diesem Zusammenhang ein Zeichenfolgenliteral verwendet wird .

Das funktioniert also sowohl bei Gawk als auch bei Mawk:

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

wie das:

$ ( echo .pdf; echo /pdf ) |
  awk '{ if ($0 ~ /\.pdf/) print "   match: " $0; else print "no match: " $0; }'
   match: .pdf
no match: /pdf
ilkkachu
quelle
Siehe auch austingroupbugs.net/view.php?id=1105 In der nächsten POSIX-Version wird diesbezüglich einige Änderungen vorgenommen.
Stéphane Chazelas
@ StéphaneChazelas, ich hatte gehofft, Sie hätten eine Klarstellung. (Ich habe darüber nachgedacht, ein richtiges Q daraus zu machen, habe das aber nicht geschafft.) Aber der Text in diesem Fehlerbericht ist immer noch ein bisschen zu normal für mich ... Sollte dieses Update in der Escape-Zeichentabelle verstanden werden so dass in /\[/, \[bleibt wie es ist, und dann macht der Backslash den [Verlust seiner besonderen Eigenschaften während der Regex-Verarbeitung? Damit die Absicht tatsächlich ist, dass /\[/das gleiche wie \[in grep etc tut ?
Ilkkachu
[.]ist eine besser lesbare Möglichkeit, einen Punkt abzugleichen, wie @mosvy unten erwähnt.
jrw32982 unterstützt Monica
5

Wie Sie der Tabelle hier entnehmen können, ist in einem regulären Ausdruck in awk ein Backslash, gefolgt von bis zu 3 Oktalstellen, ein weiterer Backslash oder einer der folgenden Werte nicht ["/abfnrtv]definiert.

Am besten schreiben Sie, [.]anstatt \.ein Literal zu schreiben ..

Beachten Sie, dass in diesem Fall das mawkVerhalten von der allgemeinen Praxis abweicht. Während alle awkmir bekannten Implementierungen Sie entkommen lassen \., \+können Sie \*in einem Regex-Literal ( /foo\.bar/) nur mawkinnerhalb einer Zeichenfolge, die als regulärer Ausdruck verwendet wird ( $0~"foo\.bar"), dasselbe tun .

Mosvy
quelle
Je nachdem, welche Informationen Sie benötigen, ist die Verwendung von /procoder sock_diagdirekt von Perl oder Python möglicherweise eine bessere Idee als das Parsen der Ausgabe von lsof.
Mosvy
Da bin ich mir nicht so sicher. Über der Tabelle steht "Das Dienstprogramm awk muss die erweiterte Notation für reguläre Ausdrücke [Link] verwenden, mit der Ausnahme, dass die Verwendung von Konventionen in C-Sprache zum Entkommen von Sonderzeichen zulässig ist" und hinter dem Link "Ein ERE-Sonderzeichen [.. .] Wenn ein <backslash> vorangestellt ist, muss ein solches Zeichen ein ERE sein, das dem Sonderzeichen selbst entspricht. " . Ich denke nicht, dass der erste Satz bedeuten soll, dass die Tabelle dort die übliche Bedeutung des Backslashs in ERE überschreiben sollte.
Ilkkachu
Es heißt "Die Interpretation eines gewöhnlichen Zeichens, dem ein nicht entkoppelter <Backslash> vorausgeht, ist undefiniert" , aber dann wird der Punkt explizit als Sonderzeichen aufgeführt. Hier funktioniert der Backslash gut, um dem Punkt zu entkommen (in allen Versionen von awk, die ich finden kann):echo '/pdf \.pdf' |mawk '$1 ~ $2 { print "match"; }'
ilkkachu
Diese Tabelle ist ziemlich klar (jeder Backslash, gefolgt von einem Zeichen, das nicht in dieser Tabelle enthalten ist, oder \ n, \ r, etc => undefined). Auf diese Tabelle wird auch aus der Beschreibung des STRING-Tokens verwiesen. Wie auch immer, diese Spezifikation sollte die bestehende Praxis kodifizieren, und hier ist Maul die seltsame.
Mosvy
hmm ja, das ist ein ziemlich interessanter Widerspruch. Ich frage mich, gibt es einige awk - Implementierung , die die Tabelle auf den Brief nehmen würde, und behandeln , zum Beispiel \[, \*oder \(als etwas anderes als entkommen Sonderzeichen?
Ilkkachu
2

Wie in vielen anderen Sprachen \xhat eine andere Bedeutung in Zeichenfolgen oder in regulären Ausdrücken. Sie können entweder verwenden

$NF ~ /\.pdf/

oder

$NF ~ "\\.pdf"

Die Saite "\.pdf"ist nur eine seltsame Art zu sagen".pdf"

JJoao
quelle