기본 문법
awk [옵션] '패턴 { 액션 }' 파일...
awk는 입력을 한 줄씩 읽어 구분자로 필드를 나눈 뒤, 조건(패턴)에 맞는 줄에만 동작(액션)을 수행하는 텍스트 처리 도구입니다. Rocky Linux 8에는 GNU awk(gawk)가 설치되어 있으며 `awk` 명령으로 실행됩니다(`awk`는 gawk를 가리키는 대체 링크입니다). 기본 구조는 '패턴 { 액션 }'이고, 필드는 $1, $2처럼 번호로 참조하며 $0은 줄 전체를 뜻합니다.
grep은 줄 단위 검색에, cut은 단순 열 추출에 쓰입니다. awk는 여기에 더해 조건 비교와 계산, 출력 형식 변경을 한 번에 처리할 수 있습니다. /etc/passwd 같은 콜론 구분 파일에서 특정 셸 사용자만 뽑기, CSV에서 status가 active인 행의 이름만 추출하기, 로그에서 상태 코드가 500 이상인 요청의 경로만 모으기 같은 작업이 대표적입니다.
리눅스마스터·LPIC·RHCSA 실기에서는 -F로 구분자를 지정하고 조건식과 print를 조합하는 문제가 자주 출제됩니다. 실무에서도 로그 집계, 점검 리포트 생성, sort·uniq와의 파이프 연결에 쓰이므로 기본 문법을 익혀 두면 도움이 됩니다.
자주 쓰는 옵션
| 옵션 | 의미 | 예 |
|---|---|---|
-F 구분자 | 입력 필드 구분자를 지정합니다(기본은 공백과 탭). 한 글자 또는 정규식을 쓸 수 있습니다. | awk -F: '{print $1}' /etc/passwd |
-v 변수=값 | awk 프로그램이 시작되기 전에 변수에 값을 지정합니다. | awk -v s=/bin/bash -F: '$7==s{print $1}' /etc/passwd |
-f 파일 | awk 프로그램을 명령줄 대신 지정한 파일에서 읽어 실행합니다. | awk -f prog.awk data.txt |
--version | 설치된 gawk 버전을 출력합니다. | awk --version |
BEGIN { } (옵션이 아닌 문법 요소) | 입력을 읽기 전에 한 번 실행됩니다. 헤더 출력이나 변수 초기화에 씁니다. | awk 'BEGIN{FS=":"}{print $1}' /etc/passwd |
END { } (옵션이 아닌 문법 요소) | 입력을 모두 읽은 뒤 한 번 실행됩니다. 합계나 건수 출력에 씁니다. | awk 'END{print NR}' /etc/passwd |
NR (내장 변수) | 현재까지 읽은 줄 번호입니다. END 블록에서 참조하면 전체 줄 수가 됩니다. | awk 'NR>1{print $1}' data.csv |
NF (내장 변수) | 현재 줄의 필드 개수입니다. $NF는 마지막 필드를 가리킵니다. | awk -F: 'NF==7{print $1}' /etc/passwd |
OFS (내장 변수) | 출력 필드 구분자입니다. print에서 쉼표로 나열한 값 사이에 들어갑니다. | awk -F: 'BEGIN{OFS="-"}{print $1,$3}' /etc/passwd |
printf (내장 함수) | 형식을 지정해 출력합니다. 줄바꿈은 \n으로 직접 넣어야 합니다. | awk -F: '{printf "%s:%s\n", $1, $3}' /etc/passwd |
실무 예시
특정 필드만 출력
준비: mkdir -p /tmp/demo; printf 'root:x:0:0:root:/root:/bin/bash\nbackup:x:1001:1001::/home/backup:/bin/sh\nnobody:x:65534:65534::/:/sbin/nologin\n' > /tmp/demo/passwd.sample
$ awk -F: '{print $1}' /tmp/demo/passwd.sample
root
backup
nobody
콜론을 구분자로 지정해 첫 번째 필드(사용자 이름)만 출력합니다. 실습 파일은 /tmp/demo 에 만들어 원본 /etc/passwd 를 건드리지 않습니다.
조건에 맞는 행만 추출
$ awk -F: '$7=="/bin/bash" || $7=="/bin/sh" {print $1}' /tmp/demo/passwd.sample
root
backup
7번째 필드(로그인 셸)가 /bin/bash 또는 /bin/sh 인 사용자 이름만 출력합니다. 실습 #140, #160 유형입니다.
CSV에서 조건 열 추출
준비: mkdir -p /tmp/demo; printf 'name,status,port\nsshd,active,22\nhttpd,inactive,80\nchronyd,active,323\n' > /tmp/demo/services.csv
$ awk -F, 'NR>1 && $2=="active" {print $1}' /tmp/demo/services.csv
sshd
chronyd
헤더 줄(NR==1)을 건너뛰고 status가 active인 서비스 이름만 원본 순서대로 출력합니다. 값 안에 쉼표가 들어가거나 따옴표로 묶인 CSV에는 -F, 방식이 맞지 않습니다. 실습 #148 유형입니다.
숫자 비교로 로그 필터링
준비: mkdir -p /tmp/demo; printf '10.0.0.1 GET /index.html 200\n10.0.0.2 GET /admin 500\n10.0.0.3 GET /api/v1 503\n10.0.0.4 GET /admin 500\n' > /tmp/demo/http.log
$ awk '$4 >= 500 {print $3}' /tmp/demo/http.log | sort -u
/admin
/api/v1
4번째 필드(상태 코드)가 500 이상인 줄의 경로만 뽑아 sort -u 로 정렬하고 중복을 제거합니다. 출력은 원본 순서가 아니라 사전순입니다. 실습 #165 유형입니다.
출력 형식 바꾸기와 합계
준비: mkdir -p /tmp/demo; printf 'sshd,tcp,22\nntp,udp,123\nhttp,tcp,80\n' > /tmp/demo/netsvc.csv
$ awk -F, '$2=="tcp"{printf "%s:%s\n", $1, $3; n++} END{print "tcp count=" n}' /tmp/demo/netsvc.csv
sshd:22
http:80
tcp count=2
2번째 필드가 tcp인 항목만 name:port 형식으로 출력하고, END 블록에서 건수를 표시합니다. n은 처음 쓰일 때 0으로 시작하므로 따로 초기화하지 않아도 됩니다.
주의할 점
- awk 프로그램은 작은따옴표로 감싸야 합니다. 큰따옴표를 쓰면 셸이 $1을 먼저 해석해 빈 값이 됩니다.
- -F로 구분자를 지정하지 않으면 공백과 탭을 기준으로 나뉩니다. /etc/passwd 같은 콜론 구분 파일은 -F: 가 필요합니다.
- 문자열 비교는 $7=="/bin/bash" 처럼 큰따옴표로 감싸고, = 이 아닌 == 을 써야 합니다. = 을 쓰면 비교가 아니라 대입이 되어 조건이 항상 참이 될 수 있습니다.
- print는 자동으로 줄바꿈하지만 printf는 하지 않습니다. printf에는 \n 을 직접 넣어야 합니다.
- 비교 대상이 숫자처럼 보여도 필드가 문자열로 취급되면 사전순 비교가 됩니다. 숫자 비교를 확실히 하려면 $4+0 >= 500 처럼 숫자로 변환해 비교합니다.
- /etc/passwd, /etc/shadow 같은 시스템 파일은 편집기나 리다이렉션으로 직접 고치지 말고, 읽기 전용으로만 다루거나 useradd·usermod·chsh 같은 전용 명령을 사용하세요. 실습은 /tmp 아래 복사본으로 하는 것이 안전합니다.
이 명령어로 풀 수 있는 실습 문제
브라우저 웹 터미널에서 바로 풀고 요구사항별로 자동 채점됩니다. 로그인 없이 5분 체험도 가능합니다.
관련 명령어
마지막 검수 2026-09-16 · 내용에 오류가 있으면 문제 페이지의 질문 기능으로 알려 주세요.
