리눅스 텍스트 처리 — sed, awk, cut, sort, uniq, xargs 실전 정리
파이프로 연결되는 7~8개의 작은 도구가 곧 데이터 처리 언어다. 한 줄짜리 명령으로 로그를 분석하고 CSV를 다듬는 실전 패턴 위주로 정리.
Series
리눅스 명령어 시리즈- 1man이 너무 길 때 — tldr로 리눅스 명령어 빠르게 익히기
- 2파일 검색 명령어 정리 — find, grep, fd, ripgrep
- 3리눅스 로그 보는 명령어 정리 — tail, less, journalctl, lnav
- 4리눅스 프로세스·리소스 모니터링 — top, htop, ps, df 실전 정리
- 5리눅스 권한 정리 — chmod, chown, sudo와 그 너머
- 6리눅스 네트워크 디버깅 — ss, curl, dig, tcpdump 실전 정리
- 7SSH·SCP·Rsync — 원격 접속과 파일 동기화 한 묶음
- 8리눅스 텍스트 처리 — sed, awk, cut, sort, uniq, xargs 실전 정리
공부하게 된 계기
한 번쯤 이런 경험이 있다.
"이 100MB짜리 로그에서 IP별 접속 횟수 상위 10개만 뽑아주세요."
Excel을 켜고, 데이터를 임포트하고, 피벗 테이블을 만든다. 30분이 사라진다.
리눅스 셸에서는 한 줄이면 된다.
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head이게 가능한 이유는 작은 도구들을 파이프로 엮는 철학 때문이다. 각 도구는 한 가지만 잘하고, 입력은 stdin, 출력은 stdout. 이걸 |로 이어붙이면 그 자체가 데이터 처리 언어다.
이 글은 그 묶음을 정리한다 — cut, sort, uniq, tr, sed, awk, xargs, 그리고 부수적으로 wc, paste, comm, diff.
1) cut — 컬럼 자르기
# 구분자 기준으로 N번째 컬럼
cut -d',' -f2 data.csv
# 여러 컬럼
cut -d',' -f1,3,5 data.csv
# 범위
cut -d',' -f2-4 data.csv
# 탭 구분 (기본)
cut -f1,2 tabbed.tsv
# 문자 위치로 자르기
cut -c1-10 file.txt가장 단순한 컬럼 추출. CSV·TSV의 특정 컬럼만 빠르게 빼낼 때.
공백이 여러 개로 구분된 경우(예: ps 출력)는 cut -d' '이 잘 안 먹는다 — 공백이 여러 개면 빈 컬럼이 끼기 때문. 이런 경우엔 awk가 답.
2) sort — 정렬
# 알파벳 순
sort file.txt
# 역순
sort -r file.txt
# 숫자로 정렬 (그냥 sort는 문자열로 정렬해서 "10"이 "2"보다 앞)
sort -n file.txt
# 큰 숫자 순
sort -rn file.txt
# 특정 컬럼 기준
sort -k2 file.txt # 2번째 컬럼
sort -t',' -k3 -n data.csv # CSV의 3번째 컬럼, 숫자
# 중복 제거하면서 정렬
sort -u file.txt
# 사람이 읽는 단위 (1K, 1M, 1G)
sort -h
du -sh */ | sort -rh # 큰 디렉토리 순sort -h는 du -sh 결과 정렬에 거의 매번 쓴다.
3) uniq — 중복 처리
uniq는 연속된 중복만 제거한다. 그래서 거의 항상 sort와 같이 쓴다.
# 중복 제거
sort file.txt | uniq
# 카운트 (각 줄이 몇 번 나왔는지)
sort file.txt | uniq -c
# 중복인 줄만
sort file.txt | uniq -d
# 유일한 줄만 (한 번만 등장)
sort file.txt | uniq -uIP별 접속 카운트 — 표준 패턴
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head한 줄에서 다섯 단계가 일어난다:
awk '{print $1}'— 1번째 컬럼 (IP)sort— 정렬해서 같은 IP끼리 모음uniq -c— 카운트sort -rn— 카운트 큰 순head— 상위 10개
이 패턴이 셸 텍스트 처리의 정석. 매번 보게 된다.
4) tr — 문자 치환·삭제
# 대소문자 변환
echo "Hello" | tr 'a-z' 'A-Z' # HELLO
echo "Hello" | tr 'A-Z' 'a-z' # hello
# 특정 문자 삭제
echo "abc-123" | tr -d '-' # abc123
# 여러 공백을 하나로
echo "a b c" | tr -s ' ' # a b c
# 줄바꿈을 다른 걸로
cat file.txt | tr '\n' ',' # CSV로
# CRLF → LF (Windows 파일 → Unix)
tr -d '\r' < windows.txt > unix.txtsed로도 다 할 수 있지만 단순한 문자 치환은 tr이 더 빠르고 직관적.
5) sed — 스트림 에디터
sed는 강력하지만 처음엔 부담스럽다. 일단 자주 쓰는 5개 패턴만 외우면 80%는 된다.
패턴 1: 치환
# 첫 번째 매치만 (한 줄에 여러 개 있어도 첫 개만)
sed 's/old/new/' file.txt
# 모두 (g = global)
sed 's/old/new/g' file.txt
# 대소문자 무시
sed 's/old/new/gI' file.txt패턴 2: 파일 직접 수정 (-i)
sed -i 's/old/new/g' file.txt # Linux
sed -i '' 's/old/new/g' file.txt # macOS (BSD sed — 빈 따옴표 필요)패턴 3: 특정 줄 삭제
sed '5d' file.txt # 5번째 줄
sed '5,10d' file.txt # 5~10번째 줄
sed '/^$/d' file.txt # 빈 줄 모두
sed '/pattern/d' file.txt # pattern 매치되는 줄패턴 4: 특정 줄만 출력
sed -n '10,20p' file.txt # 10~20번째 줄만
sed -n '/ERROR/p' log.txt # ERROR 포함된 줄만-n은 "기본 출력 끔", p는 "이 줄 출력".
패턴 5: 정규식과 캡처
# 그룹 캡처해서 재배열
sed -E 's/([0-9]+)-([a-z]+)/\2-\1/' file.txt
# 123-abc → abc-123-E(BSD/GNU 모두 지원)로 확장 정규식 활성화.
macOS의 sed는 GNU sed와 미묘하게 다르다. -i ''처럼 빈 인자가 필요한 점이 가장 큰 차이. 스크립트를 둘 다에서 쓰려면 gsed(brew install gnu-sed)를 깔거나, 양쪽 호환되는 문법만 쓰는 게 안전하다.
6) awk — 한 줄짜리 데이터 처리 언어
awk는 사실 언어다. 하지만 우리가 쓰는 99%는 한 줄짜리.
가장 자주 쓰는 형태
# 컬럼 출력 (기본 구분자: 공백)
awk '{print $1}' file.txt
awk '{print $1, $3}' file.txt # 1, 3번째
awk '{print $NF}' file.txt # 마지막 컬럼
# 구분자 변경
awk -F',' '{print $2}' data.csv
awk -F':' '{print $1}' /etc/passwd조건 + 액션
# 9번째 컬럼이 5로 시작하는 줄만 (5xx 응답)
awk '$9 ~ /^5/' access.log
# 9번째 컬럼이 500 이상
awk '$9 >= 500' access.log
# 두 컬럼 비교
awk '$3 > $4' data.txt
# 매칭 줄 카운트
awk '/ERROR/ {count++} END {print count}' log.txt합계·평균
# 10번째 컬럼 합계
awk '{sum += $10} END {print sum}' file.txt
# 평균
awk '{sum += $10; n++} END {print sum/n}' file.txt
# 최댓값
awk 'NR==1 || $1 > max {max=$1} END {print max}' file.txt멀티라인 — BEGIN, END
awk '
BEGIN { print "Start" }
/ERROR/ { errors++ }
/WARN/ { warnings++ }
END { print "ERROR:", errors, "WARN:", warnings }
' log.txtawk만으로 책 한 권이 나오니, 일단 {print $N}과 조건 필터링 두 가지만 자유롭게 쓰면 그 자체로 강력하다.
7) xargs — 출력을 다른 명령의 인자로
파이프는 보통 stdin → stdout이지만, 어떤 명령은 인자로만 입력을 받는다 (rm, mv, cp 등). xargs가 그 다리 역할.
# 모든 .log 파일 삭제
find . -name '*.log' | xargs rm
# 더 안전하게 (공백 포함 파일명 대응)
find . -name '*.log' -print0 | xargs -0 rm
# 한 번에 하나씩 (병렬 안 함)
find . -name '*.log' | xargs -I {} mv {} /backup/
# 병렬 실행 (-P)
find . -name '*.png' | xargs -P 4 -I {} convert {} {}.webp-I {} — 위치 지정
기본은 끝에 인자가 붙는다. -I {}로 위치를 바꿀 수 있다.
# 끝에 붙음
echo "src.txt" | xargs cp dest/ # cp dest/ src.txt — 잘못됨
# 위치 지정
echo "src.txt" | xargs -I {} cp {} dest/ # cp src.txt dest/find -exec와 xargs 어떤 걸: 단순한 경우 xargs가 빠르고 (한 번에 묶어 실행), 복잡한 경우 find -exec이 안전하다 (파일명에 특수문자 포함 시). 안전 우선이면 find -print0 \| xargs -0.
8) 그 외 자주 만나는 작은 도구들
wc — 카운트
wc -l file.txt # 줄 수
wc -w file.txt # 단어 수
wc -c file.txt # 바이트 수grep -c도 줄 수를 세지만, wc -l이 더 직관적인 경우가 많다.
paste — 옆으로 붙이기
# 두 파일을 컬럼으로 옆에 붙임
paste a.txt b.txt
# 구분자 변경
paste -d',' a.txt b.txtcomm — 두 정렬된 파일 비교
comm a.txt b.txt
# 1번 컬럼: a에만, 2번: b에만, 3번: 둘 다
# a에만 있는 줄
comm -23 a.txt b.txtdiff — 두 파일 차이
diff a.txt b.txt
diff -u a.txt b.txt # unified diff (git 스타일)
diff -r dir1 dir2 # 디렉토리 비교head / tail
3편 로그 글에서 다뤘다. 텍스트 처리에서도 자주 같이 등장.
실전 패턴 8개
A. IP별 접속 카운트 (반복)
awk '{print $1}' access.log | sort | uniq -c | sort -rn | headB. 5xx 응답 발생 시각
awk '$9 ~ /^5/ {print $4}' access.log | headC. 가장 큰 파일 10개
find . -type f -printf '%s %p\n' 2>/dev/null | sort -rn | head | awk '{printf "%.1fMB\t%s\n", $1/1024/1024, $2}'D. 코드에서 TODO 카운트 (사람별)
git blame과 조합:
git ls-files | xargs grep -nE 'TODO|FIXME' \
| awk -F: '{print $1":"$2}' \
| xargs -I {} sh -c 'echo $(git blame -L $(echo {}|cut -d: -f2),$(echo {}|cut -d: -f2) $(echo {}|cut -d: -f1) | awk -F"(" "{print \$2}" | awk "{print \$1, \$2}")' \
| sort | uniq -c | sort -rn(이런 게 가능하다는 데모 — 실전에선 더 단순하게 분리하는 게 나음.)
E. CSV에서 중복 제거 (특정 컬럼 기준)
# 1번째 컬럼 기준 첫 등장만
awk -F',' '!seen[$1]++' data.csv!seen[$1]++ 패턴 — 처음 보면 신기하지만 awk 쓰는 사람의 일상 표현.
F. 빈 줄과 주석 제거 (설정 파일 깔끔하게)
sed -e '/^#/d' -e '/^$/d' nginx.confG. 단어별 카운트 (가장 많이 쓰인 단어)
cat README.md | tr -s '[:space:]' '\n' | tr 'A-Z' 'a-z' | sort | uniq -c | sort -rn | headH. 두 디렉토리에 있는 파일 차이
diff <(ls dir1) <(ls dir2)
# 또는
comm -23 <(ls dir1 | sort) <(ls dir2 | sort)<(...)는 프로세스 치환 — 명령 출력을 임시 파일처럼 쓴다. 자주 활용된다.
정리
가장 자주 쓰는 5개:
awk '{print $N}'— 컬럼 추출sort \| uniq -c \| sort -rn— 카운트 집계sed 's/old/new/g'— 치환tr— 단순 문자 변환xargs— 출력 → 인자
이 다섯이 손에 익으면 Excel/스크립트 켤 일이 절반 이하로 줄어든다.
UNIX 철학 — "한 가지 일을 잘하는 작은 도구를 파이프로 엮는다" — 의 가장 빛나는 영역이 텍스트 처리다. 각 도구는 단순하지만, 조합의 표현력은 거의 무한하다.
시리즈 정리
8편으로 시리즈를 마무리한다.
- 1편: tldr
- 2편: 파일 검색
- 3편: 로그
- 4편: 프로세스 모니터링
- 5편: 권한
- 6편: 네트워크 디버깅
- 7편: SSH·SCP·Rsync
- 8편 (이 글): 텍스트 처리
여기까지 8편이면 일상의 90% 이상을 커버한다. 더 깊은 영역(systemd 유닛 작성, iptables, 컨테이너 런타임, eBPF 등)은 별도 시리즈로 나누는 게 자연스럽다.
참고 자료
man awk,man sed,man sort- Awk One-Liners (Eric Pement) — 한 줄 awk 패턴 모음
- Sed One-Liners (Eric Pement) — 한 줄 sed 패턴 모음
- explainshell.com — 복잡한 한 줄 명령 해부해주는 사이트