iBetter Books
수정

패턴과 액션

awk를 단순한 필터로 쓰는 것도 유용하지만, 진짜 강점은 변수, 배열, 조건문, 반복문을 갖춘 프로그래밍 언어라는 점입니다. 이 절에서는 다양한 패턴 유형과 액션 안에서 사용할 수 있는 프로그래밍 요소를 살펴봅니다.

패턴 종류

정규식 패턴.

# ERROR가 포함된 줄 출력awk '/ERROR/ { print }' /var/log/syslog# 대소문자 무시 (tolower 함수 활용)awk 'tolower($0) ~ /error/ { print }' /var/log/syslog

~는 매칭 연산자입니다. !~는 매칭되지 않는 경우입니다.

# GET 요청이 아닌 줄만 출력awk '$0 !~ /GET/' /tmp/access.log

범위 패턴.

# START 패턴부터 END 패턴까지 출력awk '/START/,/END/ { print }' file# 3번째 줄부터 7번째 줄까지awk 'NR==3,NR==7 { print }' file

비교/논리 패턴.

# 세 번째 필드가 100보다 크고, 네 번째 필드가 "A"인 줄awk '$3 > 100 && $4 == "A" { print $1 }' file# 두 번째 필드가 10 미만이거나 100 초과인 줄awk '$2 < 10 || $2 > 100 { print }' file

변수와 연산

awk 변수는 선언 없이 사용합니다. 처음 참조할 때 숫자는 0, 문자열은 빈 문자열로 초기화됩니다.

# 합계 계산awk '{ sum += $1 } END { print "합계:", sum }' /tmp/numbers.txt# 평균 계산awk '{ sum += $1; count++ } END { print "평균:", sum/count }' /tmp/numbers.txt

배열

awk 배열은 연관 배열(associative array)입니다. 문자열을 인덱스로 사용합니다.

cat > /tmp/sales.txt << 'EOF'Alice 1200Bob 800Alice 900Carol 1500Bob 600Carol 400EOF# 이름별 합계awk '{ total[$1] += $2 }END {    for (name in total) {        print name, total[name]    }}' /tmp/sales.txt
Alice 2100
Bob 1400
Carol 1900

배열을 순회하려면 for (key in array) 구문을 사용합니다. 출력 순서는 보장되지 않으므로 정렬이 필요하다면 파이프로 sort를 연결합니다.

조건문

awk -F, 'NR > 1 {    avg = ($2 + $3 + $4) / 3    if (avg >= 90) grade = "A"    else if (avg >= 80) grade = "B"    else if (avg >= 70) grade = "C"    else grade = "D"    print $1, grade}' /tmp/scores.csv
Alice B
Bob C
Carol A
Dave D

반복문

# for 반복: 각 필드 출력awk '{    for (i = 1; i <= NF; i++) {        print i, $i    }}' /tmp/scores.csv | head -8
1 이름
2 국어
3 영어
4 수학
1 Alice
2 85
3 92
4 88

while 반복.

awk 'BEGIN {    i = 1    while (i <= 5) {        print i * i        i++    }}'
1
4
9
16
25

내장 함수

함수 동작
length(s) 문자열 길이
substr(s, m, n) s의 m번째 위치에서 n글자
split(s, a, sep) s를 sep으로 분리해 배열 a에 저장
gsub(re, s) 정규식 re를 s로 전체 치환
sub(re, s) 첫 번째 매칭만 치환
sprintf(fmt, ...) 포맷 문자열 반환
tolower(s) 소문자 변환
toupper(s) 대문자 변환
index(s, t) s에서 t의 위치 반환
# 사용자 이름만 추출 (이메일에서)echo "[email protected] [email protected]" | awk '{    n = split($0, parts, " ")    for (i = 1; i <= n; i++) {        pos = index(parts[i], "@")        print substr(parts[i], 1, pos - 1)    }}'
user
admin

실습. 데이터 그룹별 집계

판매 데이터를 부서별로 집계하고, 합계 내림차순으로 정렬합니다.

cat > /tmp/dept_sales.txt << 'EOF'개발팀 Alice 1200000영업팀 Bob 2500000개발팀 Carol 980000인사팀 Dave 750000영업팀 Eve 3100000인사팀 Frank 820000개발팀 Grace 1100000EOFawk '{    dept_total[$1] += $3    dept_count[$1]++}END {    print "부서\t\t합계\t\t인원\t평균"    print "──────────────────────────────────────"    for (dept in dept_total) {        avg = dept_total[dept] / dept_count[dept]        printf "%-8s\t%10d\t%4d\t%10.0f\n",               dept, dept_total[dept], dept_count[dept], avg    }}' /tmp/dept_sales.txt | sort -k2 -rn
부서		합계		인원	평균
──────────────────────────────────────
영업팀	  5600000	   2	   2800000
개발팀	  3280000	   3	   1093333
인사팀	  1570000	   2	    785000

배열 두 개를 동시에 사용해 합계와 인원을 함께 추적했습니다. END 블록에서 평균을 계산하고 포맷에 맞춰 출력했습니다.

awk 하나로 데이터베이스 GROUP BY처럼 동작하는 집계를 만들 수 있습니다. 다음 절에서는 이 모든 기능을 종합해 실전 로그 분석 보고서를 만들어보겠습니다.