패턴과 액션
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처럼 동작하는 집계를 만들 수 있습니다. 다음 절에서는 이 모든 기능을 종합해 실전 로그 분석 보고서를 만들어보겠습니다.