백슬래시가 있는 awk FS

백슬래시가 있는 awk FS

find . -maxdepth 1 -not -type d 다음과 같은 출력을 생성하는 명령을 사용합니다../filename.1.out

find 명령 출력 awk을 . 다음을 사용하여 작동하게 했습니다../.

find . -maxdepth 1 -not -type d | gawk 'BEGIN { FS = "(\\./)|(\\.)" } ; { print NF }'

실제로 첫 번째 대괄호 세트에서 첫 번째 백슬래시를 제거하면 작동합니다. 전임자:

find . -maxdepth 1 -not -type d | gawk 'BEGIN { FS = "(\./)|(\\.)" } ; { print NF }'

이해가 안 돼요. 제 질문은 다음을 사용하면 작동하지 않는 이유입니다.

find . -maxdepth 1 -not -type d | gawk 'BEGIN { FS = "(\./)|(\.)" } ; { print NF }'

"작동하지 않는다"는 말은 NF가 두 번째 괄호가 정규 표현식인 것처럼 숫자를 반환한다는 것입니다. 문자(모든 유형의 문자와 일치) 어쩌면 내 자신의 질문에 대답하고 있을지도 모르지만... 명령/동작을 보면 초기 백슬래시가 무시되는 것 같습니다. 실제로 경고 이스케이프 시퀀스 메시지가 있습니다 \. 일반 "."으로 처리됩니다. 하지만 NF 인쇄를 시작하기 전까지는 그것이 무엇을 하는지 이해하지 못했습니다.

사실... 이스케이프 시퀀스에 대한 awk 문서(https://www.gnu.org/software/gawk/manual/html_node/Escape-Sequences.html#Escape-Sequences) 설명하다:

백슬래시 문자 자체는 일반적으로 포함될 수 없는 또 다른 문자이므로 \\문자열이나 정규식에 백슬래시를 써야 합니다.

따라서 달러 기호와 일치하는 정규식을 작성하려면 FS="\\$"?

이 글을 올리는 본래 의도는 왜 이런 일이 일어나는지 묻고자 하는 것입니다. 그럼 내가믿다내가 여러 가지를 하나로 엮었을 수도 있습니다. 내가 틀렸다면 정정해주세요.

답변1

값은 FS두 번 스캔됩니다. 첫 번째는 문자열 값으로, 두 번째는 ERE로 스캔됩니다(참조:어휘 규칙).

또한 POSIX는 , 가 , , 중 하나 가 아니고 8진수인 , , , , , , 의 \c동작 을 지정하지 않습니다 . 따라서 문자열이 ERE로 전달될지 ERE 로 전달될지 알 수 없습니다 .c"/\dddd\abfnrtv\c\cc

gawk, nawk, 그리고Brian Kernighan 자신의 버전당신에게 c, 그리고 동시에 mawk당신에게 \c:

$ for AWK in gawk mawk nawk bk-awk; do
  printf '<%s>\n' "$AWK"
  echo | "$AWK" -F '\.' '{print FS}'
done
<gawk>
gawk: warning: escape sequence `\.' treated as plain `.'
.
<mawk>
\.
<nawk>
.
<bk-awk>
.

\\항상 로 인식되므로 \안전할 것입니다 \\c.

$ for AWK in gawk mawk nawk bk-awk; do
printf '<%s>\n' "$AWK"; echo | "$AWK" -F '\\.' '{print FS}'
done
<gawk>
\.
<mawk>
\.
<nawk>
\.
<bk-awk>
\.

의 문자열 값은 \\c이므로 \cERE로 사용하면 원하는 결과를 얻을 수 있습니다.

답변2

\x이는 정규식(대부분의 쉘 및 C에서와 같이)으로 처리되기 전에 큰따옴표로 묶인 문자열의 문자가 되므로 실제로 를 입력해야 \\.합니다 \..

|이것을 테스트해 보겠습니다(대체 연산자의 우선 순위가 가장 낮으므로 괄호가 필요하지 않습니다 ).

$ echo ./a.b.c | gawk 'BEGIN { FS = "\.|\./" } { for (i=1; i<=NF; i++) { print i ": " $i } }'
gawk: cmd. line:1: warning: escape sequence `\.' treated as plain `.'
1: 
2: 
3: 
4: 
5: 
6: 
7: 

이 경고는 문자열의 이스케이프 시퀀스가 ​​중복되었음을 알려줍니다. 따라서 FS가 하는 일은 .|./각 문자를 분할하여 빈 필드를 만드는 것입니다.

이제 두 배로 늘리십시오 \.

$ echo ./a.b.c | gawk 'BEGIN { FS = "\\.|\\./" } { for (i=1; i<=NF; i++) { print i ": " $i } }'
1: 
2: a
3: b
4: c

관련 정보