왜 awk는 FS="*"를 이해할 수 있지만 FS="-*-"는 이해할 수 없나요?

왜 awk는 FS="*"를 이해할 수 있지만 FS="-*-"는 이해할 수 없나요?

내용이 다음과 같은 테스트 파일을 받았습니다.

a -*- b

사용했는데 awk 'BEGIN {FS="*"} {print $2}' test인쇄가 되네요

- b

옳은! 하지만 을 사용하면 다음과 같은 awk 'BEGIN {FS="-*-"} {print $2}' test결과를 얻습니다.

*

나는 FS정규 표현식이 지원된다는 것을 알고 있으므로 \이전에 이를 추가 했고 여전히 이 작업을 *수행 awk 'BEGIN {FS="-\*-"} {print $2}' test 하여 다음을 얻었습니다.

*

다행히 저는 반년 전에 블로그를 시작했습니다. awk 'BEGIN {FS="-[*]-"} {print $2}' test이 경우에 사용해야 한다고 언급되어 있습니다 . 그러므로 나는 다음을 얻는다:

 b

다시 정답!

*그런데 왜 FS가 그것을 이해할 수 있는지 , 이해할 수 없는지 -*-, -\*-그리고 마침내 이해할 수 있게 되었는지 정말 혼란스럽습니다 -[*]-.

메커니즘은 무엇입니까?

답변1

한 문자보다 길면 FS정규식으로 처리됩니다. of는 FS단지 *고정된 문자열로 취급되지만 FSof는 (one or more ) 와 동등한 -*-정규식입니다 . 그러므로 자신을 평범한 인물로 볼 수 있도록 허용해야 합니다 . 그리고 둘 다 이것을 할 수 있습니다. 그러나 문자열은 구문 분석됩니다.-*--+-*-\*--[*]-FS두 배- 할당할 때 한 번, 분할할 때 한 번 FS. 그렇기 때문에 이스케이프 문자 \도 이스케이프되어야 합니다.\

$ awk -F '-\\*-' '{print $2,FS}' test.txt
 b -\*-
$ awk -F '-\*-' '{print $2,FS}' test.txt
awk: warning: escape sequence `\*' treated as plain `*'
* -*-

답변2

muru의 답변에서 중요한 점 중 하나는 정규식에 백슬래시를 추가하려면 FS이중 백슬래시를 작성해야 한다는 것입니다 \\. 이는 백슬래시가 두 가지 다른 수준에서 이스케이프 문자로 사용되기 때문입니다.

문자열의 단일 백슬래시는 다음 문자를 이스케이프하는 것으로 처리되므로 정규식에서 단일 백슬래시를 얻으려면 백슬래시 자체를 이스케이프해야 합니다. 그런 다음저것백슬래시는 정규식에서 다음 문자를 이스케이프합니다.

FS='ax\*'댓글에서 말했듯이 as 와 as 사이에는 차이가 없지만 awk FS='ax*'는 경고를 인쇄합니다. 텍스트를 입력 하려면 will Split on 처럼 이중 백슬래시를 사용해야 합니다 .\***FSFS='ax\\*'ax*

아마도 몇 가지 예를 통해 이를 좀 더 명확하게 이해할 수 있을 것입니다.

#!/usr/bin/env bash

s='123abcd
123axbcd
123axxbcd
123ax*bcd
123ax**bcd'

printf "%s\n\n" "$s"

awk -F 'ax*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo


awk -F 'ax\*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax\*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo


awk -F 'ax\\*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax\\*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

산출

123abcd
123axbcd
123axxbcd
123ax*bcd
123ax**bcd

FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

awk: warning: escape sequence `\*' treated as plain `*'
FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

awk: warning: escape sequence `\*' treated as plain `*'
FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

FS=[ax\*]
[123abcd] []
[123axbcd] []
[123axxbcd] []
[123] [bcd]
[123] [*bcd]

FS=[ax\*]
[123abcd] []
[123axbcd] []
[123axxbcd] []
[123] [bcd]
[123] [*bcd]

답변3

구분 기호 내부에서 "백슬래시를 다시 이스케이프 처리해야 합니다.

$ echo 'a -*- b' | awk 'BEGIN {FS="-\\*-"} {print $2}'
 b

정규식을 FS 변수에 전달하므로 \\큰따옴표 안의 큰따옴표는 단일 백슬래시로 구문 분석되고 결과 정규식은 입력 문자열에 적용됩니다.

관련 정보