Variables
awk 는 변수를 사용할 때 일반 프로그래밍 언어와 달리 먼저 선언을 하지 않고 사용해도 됩니다. 그러면 자동으로 전역변수로 설정이 되고 프로그램이 종료될 때까지 유지가 됩니다. awk 는 변수에 타입을 두지 않기 때문에 자유롭게 숫자나 스트링을 대입해 사용할 수 있습니다. 이와같은 특징은 간단히 쉘 스크립트를 작성할 때 편리합니다.
# 동일한 변수에 숫자나 스트링을 자유롭게 대입할 수 있다.
myvar = 45; myvar = "foo bar"
awk 에서 사용하는 키워드나 함수명을 변수명으로 사용할 수 없습니다.
$ awk 'BEGIN { in = 123 }' # in 키워드
awk: cmd. line:1: BEGIN { in = 123 }
awk: cmd. line:1: ^ syntax error
# 다음은 모두 오류입니다.
$ awk 'BEGIN { index = 123 }' # index() 함수
$ awk 'BEGIN { length = 123 }' # length() 함수
$ awk 'BEGIN { func = 123 }' # func 키워드 (function 단축형)
존재하지 않는 변수는 산술연산에서는 0
과 같고 스트링 연산에서는 ""
과 같습니다.
# 현재 bb 는 존재하지 않는 변수
$ awk 'BEGIN { aa=0; if ( aa == bb ) print "yes" }'
yes
$ awk 'BEGIN { aa=""; if ( aa == bb ) print "yes" }'
yes
하지만 scalar 변수와 array 변수는 구분합니다.
awk 에서는 변수명이 처음 사용될 때 scalar 변수인지 array 변수인지가 결정됩니다. 그러므로 이후에 array 변수를 scalar 변수로 사용한다 든지 scalar 변수를 array 변수로 사용하게 되면 오류가 발생합니다. 심지어 array 변수를 delete 한 후에도 scalar 변수로 사용할 수 없습니다.
# 변수 AA 가 처음 사용될 때 array 변수로 결정됨. 이후에 scalar 변수로 사용하여 오류 발생
$ awk 'BEGIN{ AA[1]="foo"; AA="bar" }'
awk: cmd. line:1: fatal: attempt to use array 'AA' in a scalar context
# 변수 AA 가 처음 사용될 때 scalar 변수로 결정됨. 이후에 array 변수로 사용하여 오류 발생
$ awk 'BEGIN{ AA="foo"; AA[1]="bar" }'
awk: cmd. line:1: fatal: attempt to use scalar 'AA' as an array
print
문도 scalar context 이므로 array 변수를 사용할 수 없습니다.
$ awk 'BEGIN { AA[1]="foo"; print AA }'
awk: cmd. line:1: fatal: attempt to use array `AA' in a scalar context
$ awk 'BEGIN { AA[1]="foo"; print AA[1] }'
foo
$
Variables
awk 에서 사용되는 특수한 형태의 변수라고 할 수 있습니다.
레코드 값을 나타내는 $0
, 각각의 필드 값을 나타내는 $1
, $2
, $3
, ... 로 구성됩니다.
여기서 숫자 부분은 변수로 대체해 사용할 수 있습니다.
$ echo 11 22 33 | awk '{ print $1, $2, $3 }'
11 22 33
# 숫자 부분을 변수로 대체해 사용
$ echo 11 22 33 | awk '{ a=1; b=2; c=3; print $a, $b, $c }'
11 22 33
$ echo 11 22 33 | awk '{ v=1; print $(v++), $(v++), $v }'
11 22 33
# NF 는 레코드의 필드 개수를 나타내는 builtin 변수
$ echo 11 22 33 | awk '{ print $(NF-2), $(NF-1), $NF }'
11 22 33
-----------------------------------------------------------
# 50점 이하 과목이 하나라도 있는 사람 출력하기
$ cat file
이름 국어 산수 사회 자연 미술
AAA 88 76 97 78 35
BBB 77 28 56 43 55
CCC 90 65 53 80 65
$ awk 'NR!=1 {
for (i=0; NF-i > 1; i++)
if ($(NF-i) < 50) { print; next }
}' file
AAA 88 76 97 78 35
BBB 77 28 56 43 55
awk 명령에 변수값 전달 방법
awk 는 코드를 작성할 때 single quotes 을 사용하므로 본문에 shell 변수를 사용하지 못하는데요.
명령의 -v
옵션이나 인수 전달 방식을 통해서 shell 변수값을 전달할 수 있습니다.
첫 번째 방법은 데이터 파일을 awk 에 인수로 전달할 때처럼 변수값을 전달하는 방법입니다.
이렇게 전달된 변수값은 순서에 따라서 이후의 데이터 파일에 적용됩니다.
$ cat file1
file1 record 1
file1 record 2
file1 record 3
$ cat file2
file2 record 1
file2 record 2
file2 record 3
# 순서에 따라서 AA=111 값은 file1 레코드에 적용되고
# AA=222 값은 file2 에 적용되는 것을 볼 수 있습니다.
$ awk '{ print AA, $0 }' AA=111 file1 AA=222 file2
111 file1 record 1
111 file1 record 2
111 file1 record 3
222 file2 record 1
222 file2 record 2
222 file2 record 3
따라서 다음과 같이 설정하면 데이터 파일 별로 RS, FS 를 설정할 수 있습니다.
# file1 에는 RS='#' FS=',' 값이 적용되고
# file2 에는 RS='@' FS=':' 값이 적용된다.
$ awk '{ . . . }' RS='#' FS=',' file1 RS='@' FS=':' file2
BEGIN 블록은 레코드를 읽어들여 명령 사이클을 시작하기 전에 실행되므로
위와 같이 설정한 변수는 BEGIN 블록에는 적용되지 않는데요.
소스코드 전체에 적용시키려면 awk 명령의 -v
옵션을 사용해야 합니다.
$ awk 'BEGIN{ print AA, BB }' AA=11 BB=22
$
$ awk -v AA=11 -v BB=22 'BEGIN{ print AA, BB }'
11 22
마지막으로 FS 변수는 자주 사용되므로 따로 -F
옵션을 두고 있습니다.
$ awk -F, 'BEGIN{ print "FS is: " FS }'
FS is: ,
# FS 값은 ',' or ':'
$ awk -F ',|:' 'BEGIN{ print "FS is: " FS }'
FS is: ,|:
awk 에 shell 변수값을 전달할 때 주의할 점
awk 에 변수값을 전달할 때 사용하는 =
문자는 shell 에서 사용하는 대입 연산자가 아닙니다.
그러므로 전달하고자 하는 변수값이 공백으로 분리되어 있으면 double quotes 을 해야
오류가 생기지 않습니다.
$ MYVAR="foo bar" # shell 변수
# -v AA=$MYVAR 는 -v AA=foo bar 와 같게 되므로 오류가 발생합니다.
$ awk -v AA=$MYVAR 'BEGIN { ... }' # error !
# double quotes 을 해야 합니다.
$ awk -v AA="$MYVAR" 'BEGIN { ... }' # OK
$ awk -v "AA=$MYVAR" 'BEGIN { ... }' # OK
SYMTAB 변수를 이용한 indirection
awk 는 프로그램을 실행하기 전에 먼저 전체 코드를 읽어들여 파싱 하는데요.
이때 빌드 된 심볼 테이블을 SYMTAB
built-in 변수를 통해 접근할 수가 있습니다.
이 변수를 이용하면 일종의 indirection 을 할 수 있습니다.
$ awk '
BEGIN {
foo = 100
SYMTAB["foo"] = 200
print foo
bar[2] = 300
SYMTAB["bar"][2] = 400
print bar[2]
}'
200
400
$ awk '
BEGIN {
answer = 10.5
multiply("answer", 4)
print "The answer is", answer
}
func multiply(var, amount) {
SYMTAB[var] *= amount
}'
The answer is 42