Escape sequences
awk 를 처음 시작할 때 많이 실수하는 부분이 FS
, RS
변수를 설정할 때
사용하는 escape sequence 부분입니다.
awk 에서는 기본적으로 스트링이 double quotes 안에서 처리됩니다.
따라서 escape 할때 사용되는 \
문자가 awk 에 전달되려면 \\
두개를 사용해야 합니다.
$ echo '111(222)333' | awk -F '\(|\)' '{print $2}' # wrong
awk: warning: escape sequence `\(' treated as plain `('
awk: warning: escape sequence `\)' treated as plain `)'
$ echo '111(222)333' | awk -F '\\(|\\)' '{print $2}' # good
222
아래 escape sequence 테이블에 있는 문자를 사용할 때는 \
하나만 사용해도 되지만
그 외 regex 에서 사용되는 특수문자를 escape 한다던지 할때는 \\
두개를 사용해야 합니다.
Escape Sequence | Character represented |
---|---|
\\ | \ 문자 |
\a | alert (bell) |
\b | backspace |
\f | form feed |
\n | newline |
\r | carriage return |
\t | horizontal tab |
\v | vertical tab |
\NNN | 8 진수 ASCII 문자 NNN |
\xHH | 16 진수 ASCII 문자 HH |
\/ | regex 상수에서 사용되는 / 문자 |
\" | double quotes 에서 사용되는 " 문자 |
예를 들어 newline 이나 tab 문자를 설정하는 경우는 다음과 같이 두 가지 형태가 모두 가능합니다.
첫 번째 경우는 double quotes 에서 escape sequence 가 처리되여 직접 newline, tab 문자가 전달되는 경우고
두 번째는 FS 값이 \t
, \n
와 같이 escape sequence 형태로 전달됩니다.
$ awk -F '\t' '{ ... }' # 첫 번째 OK
$ awk -F '\\t' '{ ... }' # 두 번째 OK
$ awk 'BEGIN{ FS="\n" } ...' # OK
$ awk 'BEGIN{ FS="\\n" } ...' # OK
변수값 설정시 escape sequence 사용
RS, FS 같은 변수는 설정된 값이 문자가 두개 이상이면 regex 로 해석됩니다. 따라서 regex 에서 사용되는 문자를 일반 문자로 사용하려면 escape 해야 합니다.
# '**' 를 FS 로 사용. '*' 는 regex 문자이므로 일반 문자로 사용하기 위해서 escape
$ awk 'BEGIN{ FS="*\\*" } ...'
$ echo '111****333**444' | awk 'BEGIN{ FS="*\\*" } {print NF}'
4
$ echo '111****333**444' | awk 'BEGIN{ FS="**" } {print NF}'
3
awk 소스코드 외부에서 -v
옵션 등을 이용해 값을 설정할 때는 shell quotes 을 사용하는 것입니다.
이때는 설정되는 값이 그대로 awk 스트링 double quotes 안으로 전달된다고 생각하면 됩니다.
따라서 shell 변수를 사용해야 되는 경우가 아니면 single quotes 을 이용해 작성하는 것이 좋습니다.
# single quotes 을 이용하면 awk 소스코드 내에서 작성하는 것과 동일하게 작성할 수 있습니다.
$ awk -F '*\\*' 'BEGIN{...}' ...
$ awk -F '\t' 'BEGIN{...}' ...
$ awk -F '\\t' 'BEGIN{...}' ...
------------------------------------
# 만약에 double quotes 을 사용한다면 다음과 같이 해야 합니다.
# shell double quotes 에서도 \ 가 처리되므로
$ awk -F "*\\\\*" 'BEGIN{...}' ...
16 진수 형식 사용시 문제점
구 버전의 awk 에서 \xHH
16 진수 형식을 이용해 값을 출력할 때 주의할 점이 하나 있습니다.
\xHH
뒤에 바로 붙여서 16 진수에 해당하는 문자( 0-9a-fA-F )가 오면 정상적으로 값이 출력 되지 않습니다.
참고로 gawk 4.2.1 버전에서는 문제가 해결되었다고 합니다.
# "K" 는 16 진수 문자에 해당되지 않으므로 정상적으로 출력된다.
$ awk 'BEGIN { print "\x41\x42\x43KKK" }' | od -a
0000000 A B C K K K nl
0000007
# "F" 는 16 진수 문자에 해당되므로 정상적으로 값이 출력되지 않는다.
$ awk 'BEGIN { print "\x41\x42\x43FFF" }' | od -a
0000000 A B del nl
0000004
shell 에서 echo, printf 명령을 사용할 때는 이와 같은 현상이 발생하지 않으므로
프로그램 버그나 오류인 줄 알았는데
POSIX 에서는 \xHH
형식을 이용한 16 진수 출력을 허용하지 않기 때문이라고 합니다.
$ awk --lint 'BEGIN { print "\x41\x42\x43FFF" }' | od -a
awk: cmd. line:1: warning: POSIX does not allow '\x' escapes
awk: cmd. line:1: warning: hex escape \x43FFF of 5 characters probably
not interpreted the way you expect
0000000 A B del nl
0000004
8 진수 형식의 경우는 이와 같은 문제가 발생하지 않으므로 8 진수 형식을 사용하거나 아니면 다음과 같이 분리해 사용하면 되겠습니다.
# 8 진수 형식의 경우는 그런 문제가 없다.
awk 'BEGIN { print "\101\102\103FFF" }' | od -a
0000000 A B C F F F nl
0000007
# 또는 quotes 을 이용해 분리해 사용하면 된다.
$ awk 'BEGIN { print "\x41\x42\x43""FFF" }' | od -a
0000000 A B C F F F nl
0000007