정규식 `"\.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는 이전에 나열된 문자 중 하나가 아닌 문자열 상수의 문자 앞에 백슬래시를 넣으면 어떤 일이 발생하는지 의도적으로 정의되지 않은 상태로 둡니다. 두 가지 옵션이 있습니다:

백슬래시 제거
이것이 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

작업에 적합한 도구를 사용하십시오. 다음 두 가지 표현이 있습니다.

$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"

관련 정보