CS학습5 min read
awk: 줄 단위로 텍스트를 필드로 쪼개 처리하는 패턴-액션 언어
awk는 입력을 레코드(줄)와 필드(열)로 나누어 "패턴 { 액션 }" 규칙을 적용하는 텍스트 처리 언어다. 로그, CSV, 명령어 출력처럼 열 구조가 있는 텍스트에서 특정 열 추출, 조건 필터링, 합계·평균 같은 집계를 한 줄 명령으로 수행할 수 있다. 파이프라인에서 grep과 cut으로 부족한 부분을 채우는 도구로 자주 쓰인다.
By 송민성
1. 개념
awk는 텍스트를 한 줄씩 읽어 규칙에 따라 처리하는 스크립트 언어이자 명령행 도구다. 이름은 개발자인 Aho, Weinberger, Kernighan의 머리글자에서 왔다.
핵심 구조는 패턴-액션(pattern-action) 규칙이다.
text
pattern { action }- 입력의 각 줄을 레코드(record)라고 한다.
- 각 레코드는 구분자로 나뉜 필드(field)로 쪼개진다. 기본 구분자는 공백과 탭이다.
- 패턴이 참이면 액션을 실행한다. 패턴을 생략하면 모든 줄에 액션을 적용하고, 액션을 생략하면 일치하는 줄을 그대로 출력한다.
주요 내장 변수는 다음과 같다.
| 변수 | 의미 |
|---|---|
| $0 | 현재 줄 전체 |
| $1, $2, ... | 첫 번째, 두 번째, ... 필드 |
| NF | 현재 줄의 필드 수(Number of Fields) |
| NR | 지금까지 읽은 전체 줄 번호(Number of Records) |
| FS | 입력 필드 구분자(Field Separator) |
| OFS | 출력 필드 구분자(Output Field Separator) |
2. 왜 사용하는가
cut은 구분자가 여러 개의 공백일 때 다루기 불편하고,grep은 줄 전체만 걸러낼 뿐 열 단위 연산을 못 한다.- awk는 조건 필터링, 열 추출, 산술 계산, 집계를 하나의 명령으로 처리한다.
- 별도 스크립트 파일이나 컴파일 없이 터미널에서 바로 실행할 수 있다.
- 대부분의 Linux/macOS 환경에 기본 설치되어 있어 서버에서 추가 설치 없이 쓸 수 있다.
3. 동작 원리
awk의 실행은 세 단계로 이루어진다.
- BEGIN 블록: 입력을 읽기 전에 한 번 실행된다. 변수 초기화, 헤더 출력에 쓴다.
- 메인 루프: 입력의 각 레코드마다
FS로 필드를 나누고, 모든pattern { action }규칙을 위에서부터 차례로 평가한다. - END 블록: 모든 입력을 처리한 뒤 한 번 실행된다. 합계, 평균 같은 최종 결과를 출력한다.
변수는 선언 없이 쓸 수 있고, 초기값은 빈 문자열이면서 숫자로는 0으로 취급된다. 그래서 sum += $3 같은 누적이 초기화 없이도 동작한다. 연관 배열(associative array)을 기본 제공하므로 count[$1]++처럼 키별 집계도 간단하다.
4. 코드 예제
먼저 실습용 파일을 만든다.
shell
cat > access.log <<'EOF'
10.0.0.1 GET /index.html 200 512
10.0.0.2 POST /api/login 401 128
10.0.0.1 GET /api/users 200 2048
10.0.0.3 GET /missing 404 64
10.0.0.2 GET /api/users 500 0
EOF특정 열 출력:
shell
awk '{ print $1, $3 }' access.log조건 필터링(상태 코드가 400 이상인 줄):
shell
awk '$4 >= 400' access.log헤더와 합계 출력(BEGIN / END):
shell
awk 'BEGIN { print "총 바이트 계산" }
{ sum += $5 }
END { print "합계:", sum, "평균:", sum / NR }' access.logIP별 요청 수 집계(연관 배열):
shell
awk '{ count[$1]++ } END { for (ip in count) print ip, count[ip] }' access.log구분자 지정(CSV, 쉼표 기준):
shell
printf 'name,age\nkim,30\nlee,25\n' | awk -F, 'NR > 1 { print $1 "의 나이는 " $2 }'명령어 출력과 조합(메모리 사용량이 큰 프로세스):
shell
ps aux | awk 'NR > 1 && $4 > 1.0 { print $2, $4, $11 }'5. 시간 복잡도 또는 성능 특성
- awk는 입력을 처음부터 끝까지 한 번 순차적으로 읽으므로, 줄 수를 n이라 하면 기본 처리 비용은 O(n)이다. 규칙이 k개면 줄마다 규칙을 평가하므로 대략 O(n·k)다.
- 연관 배열의 삽입과 조회는 해시 테이블 기반이라 평균적으로 O(1)이다.
- 입력을 스트림으로 처리하므로 파일 전체를 메모리에 올리지 않는다. 단, 배열에 모든 키를 쌓는 경우 고유 키 수만큼 메모리를 쓴다.
- 구현체(gawk, mawk, BWK awk)마다 속도 차이가 있으므로, 대용량 처리에서는 실제 환경에서 측정하는 것이 정확하다.
6. 실무 사용 사례
- 로그 분석: 상태 코드별 요청 수, 응답 시간 평균, 특정 IP의 트래픽 합계 계산
- CSV/TSV 가공: 특정 열 추출, 조건에 맞는 행 필터링
- 명령어 출력 정리:
df -h,ps,docker ps같은 출력에서 필요한 열만 뽑아 다른 명령에 전달 - 배포/운영 스크립트: 한 줄짜리 집계를 셸 스크립트 안에서 간결하게 처리
shell
# 5xx 에러 비율 계산
awk '$4 >= 500 { err++ } END { printf "5xx 비율: %.1f%%\n", err / NR * 100 }' access.log7. 주의할 점
- 셸 따옴표: awk 프로그램은 작은따옴표(
'...')로 감싸야$1이 셸 변수로 해석되지 않는다. 셸 변수를 넘기려면-v name="$value"옵션을 쓴다. - 필드 인덱스는 1부터 시작한다.
$0은 줄 전체다. - CSV의 따옴표 처리: 필드 안에 쉼표가 있는 CSV(
"a,b",c)는-F,로 올바르게 나눌 수 없다. 이런 데이터는 전용 파서를 쓰는 편이 안전하다. - 문자열 vs 숫자 비교: 입력 필드가 숫자처럼 보이면 숫자로 비교되지만, 그렇지 않으면 문자열 비교가 된다. 의도하지 않은 결과가 나오면
$4 + 0처럼 숫자로 변환해 확인한다. - 구현체 차이:
gawk전용 기능(asort,strftime등)은 macOS 기본 awk나 mawk에서 동작하지 않을 수 있다. - 배열 순회 순서:
for (k in arr)의 순회 순서는 보장되지 않는다. 정렬이 필요하면| sort로 넘긴다.
8. 핵심 정리
- awk는 입력을 레코드(줄)와 필드(열)로 나누고
pattern { action }규칙을 적용하는 도구다. $0,$1~$NF,NR,NF,FS를 알면 대부분의 작업을 처리할 수 있다.BEGIN은 시작 전,END는 종료 후에 한 번 실행되어 초기화와 집계 출력에 쓴다.- 연관 배열로 키별 카운트와 합계를 간단히 구할 수 있다.
- 처리 비용은 입력 크기에 비례(O(n))하며 스트림 방식이라 메모리 부담이 적다.
- 셸 따옴표, CSV 따옴표 필드, 구현체 차이를 주의해야 한다.