이미지 로딩 중...

고급 텍스트 처리 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 18. · 3 Views

고급 텍스트 처리 완벽 가이드

리눅스의 강력한 텍스트 처리 도구인 sed와 awk를 마스터해보세요. 로그 파일 분석부터 데이터 추출까지, 실무에서 바로 활용할 수 있는 필수 명령어와 패턴을 초급자도 쉽게 이해할 수 있도록 설명합니다.


목차

  1. sed 기본 명령어 (s, d, p)
  2. sed로 파일 내용 수정
  3. awk 기본 구조
  4. awk 필드와 레코드 처리
  5. awk 패턴과 액션
  6. 실전 로그 파싱 예제

1. sed 기본 명령어 (s, d, p)

시작하며

여러분이 서버 로그 파일에서 특정 IP 주소를 모두 다른 주소로 바꿔야 하는 상황을 겪어본 적 있나요? 수천 줄의 파일을 일일이 편집기로 열어서 찾기-바꾸기를 하는 것은 정말 비효율적입니다.

이런 문제는 실무에서 매일 발생합니다. 설정 파일 수정, 로그 정제, 데이터 변환 등 텍스트를 빠르게 처리해야 하는 상황은 끝이 없죠.

파일을 열지 않고도 원하는 작업을 할 수 있다면 얼마나 좋을까요? 바로 이럴 때 필요한 것이 sed입니다.

sed는 Stream Editor의 약자로, 파일을 열지 않고도 텍스트를 자유자재로 수정할 수 있게 해주는 마법 같은 도구입니다.

개요

간단히 말해서, sed는 텍스트를 줄 단위로 읽어서 원하는 변환을 적용하는 도구입니다. 마치 공장의 컨베이어 벨트처럼, 텍스트 라인이 하나씩 들어오면 여러분이 지정한 규칙에 따라 변환해서 내보냅니다.

왜 이 도구가 필요할까요? 실무에서는 수백만 줄의 로그를 분석하거나, 여러 설정 파일을 일괄 수정해야 하는 경우가 많습니다.

예를 들어, 개발 서버 주소를 운영 서버 주소로 바꾸거나, 민감한 정보를 마스킹 처리할 때 매우 유용합니다. 기존에는 파일을 편집기로 열어서 직접 수정했다면, 이제는 한 줄의 명령어로 순식간에 처리할 수 있습니다.

더 놀라운 것은 원본 파일을 건드리지 않고도 결과를 확인할 수 있다는 점입니다. sed의 핵심 명령어는 s(치환), d(삭제), p(출력) 세 가지입니다.

s는 텍스트를 찾아서 바꾸고, d는 특정 줄을 삭제하며, p는 특정 줄만 출력합니다. 이 세 가지만 잘 알아도 대부분의 텍스트 처리 작업을 해결할 수 있습니다.

코드 예제

# s 명령어: 첫 번째 매칭되는 문자열을 치환
echo "hello world hello" | sed 's/hello/hi/'

# g 플래그: 모든 매칭 문자열 치환
echo "hello world hello" | sed 's/hello/hi/g'

# d 명령어: 특정 패턴이 있는 줄 삭제
sed '/error/d' server.log

# p 명령어: 특정 패턴이 있는 줄만 출력 (-n 옵션 필수)
sed -n '/warning/p' app.log

# 줄 번호로 작업: 3번째 줄 삭제
sed '3d' file.txt

# 범위 지정: 5번째부터 10번째 줄만 출력
sed -n '5,10p' file.txt

설명

이것이 하는 일: sed는 텍스트를 한 줄씩 읽어서 여러분이 지정한 명령을 실행하고 결과를 출력합니다. 원본 파일은 그대로 두고 변환된 결과만 화면에 보여주는 것이 기본 동작입니다.

첫 번째로, s 명령어는 substitute(치환)의 약자입니다. sed 's/찾을내용/바꿀내용/' 형식으로 사용하며, 기본적으로 각 줄에서 첫 번째로 매칭되는 것만 바꿉니다.

왜 이렇게 할까요? 실수로 모든 것을 바꾸는 것을 방지하기 위해서입니다.

모든 매칭을 바꾸려면 끝에 g(global) 플래그를 붙입니다. 그 다음으로, d 명령어가 실행되면 해당 조건에 맞는 줄은 출력되지 않습니다.

/error/d라고 하면 "error"라는 단어가 포함된 모든 줄이 제거됩니다. 내부적으로는 그 줄을 읽었지만 출력 단계에서 건너뛰는 방식으로 동작합니다.

마지막으로, p 명령어는 print(출력)를 의미하며, 반드시 -n 옵션과 함께 사용해야 합니다. -n 없이 사용하면 모든 줄이 출력된 후 매칭된 줄이 한 번 더 출력되어 중복이 발생합니다.

-n은 "자동 출력을 끄라"는 의미입니다. 여러분이 이 명령어들을 사용하면 대용량 로그 파일에서 에러만 추출하거나, 설정 파일의 특정 값을 일괄 변경하거나, 불필요한 줄을 제거하는 등의 작업을 몇 초 만에 완료할 수 있습니다.

파일을 열지 않아도 되니 메모리도 절약되고, 명령어 히스토리에 남아서 나중에 재사용도 쉽습니다.

실전 팁

💡 -i 옵션을 사용하면 파일을 직접 수정할 수 있지만, -i.bak처럼 백업 확장자를 지정하는 습관을 들이세요. 실수로 중요한 파일을 망가뜨리는 것을 방지할 수 있습니다.

💡 정규표현식을 사용할 때는 /^error/ (줄 시작), /error$/ (줄 끝)처럼 앵커를 활용하면 더 정확한 매칭이 가능합니다.

💡 여러 명령을 실행하려면 -e 옵션을 사용하거나 세미콜론으로 구분하세요: sed 's/foo/bar/; s/old/new/'

💡 대소문자를 구분하지 않으려면 I 플래그를 사용하세요: sed 's/error/ERROR/gI'

💡 sed 명령을 실행하기 전에 먼저 sed -n '/pattern/p'로 어떤 줄이 영향을 받을지 미리 확인하는 습관을 들이세요.


2. sed로 파일 내용 수정

시작하며

여러분이 100개의 설정 파일에서 서버 주소를 한꺼번에 바꿔야 한다고 상상해보세요. 각 파일을 열어서 수정하고 저장하는 작업을 100번 반복해야 한다면 정말 끔찍하겠죠?

이런 반복 작업은 실제로 배포 환경을 바꾸거나, 대규모 리팩토링을 할 때 자주 발생합니다. 사람이 직접 하면 실수도 생기고 시간도 오래 걸립니다.

게다가 나중에 똑같은 작업을 또 해야 할 수도 있습니다. 바로 이럴 때 필요한 것이 sed의 파일 수정 기능입니다.

원본을 안전하게 백업하면서 동시에 여러 파일을 일괄 수정할 수 있는 강력한 기능을 제공합니다.

개요

간단히 말해서, sed의 -i 옵션은 "in-place" 수정을 가능하게 합니다. 이것은 파일을 직접 열어서 수정한 것처럼 원본 파일 자체를 변경하는 기능입니다.

왜 이 기능이 중요할까요? 실무에서는 단순히 결과를 화면에 출력하는 것보다 파일을 실제로 수정해야 하는 경우가 훨씬 많습니다.

예를 들어, API 엔드포인트 URL을 변경하거나, 데이터베이스 접속 정보를 업데이트하거나, 코드에서 deprecated된 함수를 새 함수로 바꿀 때 매우 유용합니다. 기존에는 sed 's/old/new/' file.txt > temp.txt && mv temp.txt file.txt처럼 복잡하게 했다면, 이제는 sed -i 's/old/new/' file.txt 한 줄이면 됩니다.

훨씬 간단하고 실수할 여지도 줄어듭니다. sed 파일 수정의 핵심 특징은 세 가지입니다.

첫째, 자동 백업 기능으로 원본을 안전하게 보존할 수 있습니다. 둘째, 여러 파일을 동시에 처리할 수 있습니다.

셋째, 복잡한 변환도 한 번의 명령으로 처리 가능합니다. 이러한 특징들이 여러분의 작업 시간을 수십 배 단축시켜줍니다.

코드 예제

# 파일을 직접 수정 (위험! 백업 없음)
sed -i 's/localhost/production.server.com/' config.ini

# 백업을 만들면서 수정 (.bak 파일 생성)
sed -i.bak 's/localhost/production.server.com/' config.ini

# 여러 파일을 한번에 수정
sed -i.bak 's/old-api/new-api/g' *.js

# 여러 변환을 동시에 적용
sed -i.bak -e 's/foo/bar/g' -e 's/hello/hi/g' file.txt

# 특정 줄만 수정: 10번째 줄의 텍스트 치환
sed -i.bak '10s/old/new/' config.txt

# 특정 패턴이 있는 줄만 수정
sed -i.bak '/database/s/localhost/db.server.com/' settings.conf

설명

이것이 하는 일: sed의 -i 옵션은 파일을 메모리에 읽어들여 변환을 적용한 후, 원본 파일을 덮어쓰는 방식으로 동작합니다. 백업 확장자를 지정하면 덮어쓰기 전에 원본을 백업 파일로 복사합니다.

첫 번째로, -i 옵션만 사용하면 원본 파일이 완전히 사라지고 수정된 내용으로 교체됩니다. 이것은 매우 위험할 수 있습니다.

실수로 잘못된 명령을 실행하면 원본을 복구할 방법이 없기 때문입니다. 따라서 실무에서는 거의 사용하지 않습니다.

그 다음으로, -i.bak 형식으로 백업 확장자를 지정하면 sed가 내부적으로 file.txtfile.txt.bak으로 먼저 복사합니다. 그런 다음 변환된 내용을 file.txt에 씁니다.

이렇게 하면 문제가 생겼을 때 .bak 파일로 쉽게 복구할 수 있습니다. 세 번째로, 여러 파일을 한꺼번에 처리할 때는 와일드카드(*)를 사용합니다.

*.js라고 하면 현재 디렉토리의 모든 JavaScript 파일이 대상이 됩니다. sed는 각 파일을 순차적으로 처리하며, 각각에 대해 백업을 만들어줍니다.

마지막으로, -e 옵션을 여러 번 사용하면 하나의 명령에서 여러 변환을 순차적으로 적용할 수 있습니다. 예를 들어, sed -i -e 's/foo/bar/' -e 's/bar/baz/'는 먼저 foo를 bar로 바꾼 후, 그 결과에서 bar를 baz로 바꿉니다.

순서가 중요하다는 점을 기억하세요. 여러분이 이 기능을 사용하면 대규모 코드 마이그레이션, 설정 파일 일괄 업데이트, 데이터 정제 작업 등을 몇 분 만에 완료할 수 있습니다.

스크립트로 만들어두면 같은 작업을 반복할 때 버튼 하나로 실행할 수 있어 생산성이 크게 향상됩니다.

실전 팁

💡 중요한 파일을 수정하기 전에는 반드시 -i.bak 형식으로 백업을 만드세요. 백업이 필요 없다고 확신할 때만 -i만 사용하세요.

💡 와일드카드를 사용하기 전에 ls *.js 같은 명령으로 어떤 파일들이 영향을 받을지 먼저 확인하세요.

💡 Git을 사용한다면 먼저 커밋한 후 sed를 실행하세요. 문제가 생기면 git checkout .으로 쉽게 되돌릴 수 있습니다.

💡 -i 옵션은 표준 입력(stdin)과 함께 사용할 수 없습니다. 파이프나 리다이렉션이 필요하면 -i를 빼고 사용하세요.

💡 대규모 파일을 수정할 때는 먼저 작은 테스트 파일로 명령어를 검증한 후 실제 파일에 적용하는 습관을 들이세요.


3. awk 기본 구조

시작하며

여러분이 CSV 파일에서 특정 컬럼의 값만 추출해야 하는 상황을 떠올려보세요. 3번째 컬럼의 숫자들을 모두 더해서 평균을 구해야 한다면 어떻게 하시겠어요?

이런 데이터 처리 작업은 로그 분석, 통계 산출, 보고서 생성 등에서 매일 발생합니다. 프로그래밍 언어로 파일을 읽어서 파싱하는 코드를 작성할 수도 있지만, 간단한 작업에 너무 많은 코드가 필요합니다.

바로 이럴 때 필요한 것이 awk입니다. awk는 데이터를 자동으로 컬럼 단위로 나눠주고, 각 줄에 대해 원하는 작업을 쉽게 수행할 수 있게 해주는 강력한 텍스트 처리 언어입니다.

개요

간단히 말해서, awk는 "패턴 { 액션 }" 구조로 동작하는 텍스트 처리 프로그래밍 언어입니다. 마치 "이런 줄을 발견하면 { 이런 일을 해라 }" 같은 규칙을 정의하는 것이죠.

왜 awk가 필요할까요? sed가 줄 단위 처리에 강하다면, awk는 컬럼(필드) 단위 처리에 특화되어 있습니다.

실무에서는 공백이나 특정 구분자로 나뉜 데이터를 다루는 경우가 많은데, awk는 이것을 자동으로 처리해줍니다. 예를 들어, 웹 서버 액세스 로그에서 IP 주소만 추출하거나, 매출 데이터에서 특정 조건의 합계를 구할 때 매우 유용합니다.

기존에는 Python이나 Perl 같은 언어로 파일을 읽고 split()하고 반복문을 돌려야 했다면, 이제는 awk 한 줄이면 됩니다. 훨씬 빠르고 간결합니다.

awk의 핵심 특징은 세 가지입니다. 첫째, 자동 필드 분리 기능으로 $1, $2, $3 같은 변수로 각 컬럼에 접근할 수 있습니다.

둘째, BEGIN과 END 블록으로 전처리와 후처리를 할 수 있습니다. 셋째, 내장 변수와 함수가 풍부해서 복잡한 연산도 쉽게 처리됩니다.

이러한 특징들이 awk를 데이터 처리의 스위스 아미 나이프로 만들어줍니다.

코드 예제

# 기본 구조: 패턴 없이 모든 줄에 액션 적용
awk '{ print $1 }' file.txt

# BEGIN 블록: 데이터 처리 전에 실행
awk 'BEGIN { print "Name\tScore" } { print $1, $2 }' scores.txt

# END 블록: 데이터 처리 후에 실행
awk 'BEGIN { sum=0 } { sum+=$2 } END { print "Total:", sum }' numbers.txt

# 패턴과 액션 조합: 특정 조건의 줄만 처리
awk '/error/ { print $1, $3 }' log.txt

# 필드 구분자 지정: -F 옵션
awk -F: '{ print $1, $3 }' /etc/passwd

# 여러 액션 사용
awk '{ print "Line:", NR, "Fields:", NF, "Content:", $0 }' file.txt

설명

이것이 하는 일: awk는 파일을 한 줄씩 읽으면서 각 줄을 자동으로 필드(컬럼)로 나누고, 여러분이 정의한 패턴에 맞는 줄에 대해서만 액션을 실행합니다. 마치 스프레드시트를 한 행씩 처리하는 것과 비슷합니다.

첫 번째로, { print $1 }에서 $1은 첫 번째 필드(컬럼)를 의미합니다. awk는 기본적으로 공백(스페이스나 탭)을 구분자로 사용해서 각 줄을 자동으로 쪼갭니다.

$0은 전체 줄, $1은 첫 번째 단어, $2는 두 번째 단어... 이런 식입니다.

왜 자동으로 나눠줄까요? 대부분의 텍스트 데이터가 이런 형태이기 때문입니다.

그 다음으로, BEGIN 블록은 첫 번째 줄을 읽기 전에 단 한 번만 실행됩니다. 헤더를 출력하거나 변수를 초기화할 때 사용합니다.

반대로 END 블록은 마지막 줄까지 모두 처리한 후에 실행됩니다. 합계나 평균 같은 최종 결과를 출력할 때 유용합니다.

세 번째로, 패턴 부분에 /error/처럼 정규표현식을 쓰면 그 패턴이 포함된 줄만 처리합니다. 패턴을 생략하면 모든 줄이 대상입니다.

조건식도 사용할 수 있어서 $3 > 100 { print $1 }처럼 "3번째 필드가 100보다 크면 1번째 필드 출력"도 가능합니다. 마지막으로, NR(Number of Records)은 현재 줄 번호, NF(Number of Fields)는 현재 줄의 필드 개수를 의미하는 내장 변수입니다.

이런 변수들이 자동으로 관리되기 때문에 여러분은 비즈니스 로직에만 집중할 수 있습니다. 여러분이 awk를 사용하면 복잡한 데이터 처리 스크립트를 몇 줄로 줄일 수 있고, 파일을 열지 않고도 원하는 정보를 즉시 추출할 수 있습니다.

특히 대용량 로그 파일을 분석할 때 Python보다 훨씬 빠른 성능을 보여줍니다.

실전 팁

💡 awk 스크립트가 길어지면 작은따옴표 안에 쓰는 대신 파일로 만들어서 awk -f script.awk data.txt처럼 실행하세요. 가독성과 재사용성이 높아집니다.

💡 디버깅할 때는 각 단계마다 print로 중간 값을 출력해보세요. { print "Debug:", $1, $2; actual_code }

💡 CSV 파일을 처리할 때는 -F,로 쉼표를 구분자로 지정하세요. TSV는 -F'\t'를 사용합니다.

💡 복잡한 조건은 && (AND), || (OR)로 연결할 수 있습니다: $1 == "error" && $3 > 100 { print }

💡 awk는 자동으로 숫자와 문자열을 변환해주지만, 예상치 못한 결과를 방지하려면 명시적으로 int()나 sprintf()를 사용하세요.


4. awk 필드와 레코드 처리

시작하며

여러분이 웹 서버 로그에서 각 IP 주소별 요청 횟수를 세어야 한다고 상상해보세요. 로그의 첫 번째 컬럼이 IP 주소라면, 같은 IP가 나올 때마다 카운트를 올려야 합니다.

이런 그룹핑과 집계 작업은 데이터 분석의 기본입니다. 로그 분석, 성능 모니터링, 사용자 행동 분석 등 거의 모든 분야에서 필요한 작업이죠.

하지만 수백만 줄의 데이터를 수작업으로 처리할 수는 없습니다. 바로 이럴 때 필요한 것이 awk의 필드와 레코드 처리 기능입니다.

연관 배열(해시맵)을 사용해서 데이터를 그룹화하고, 각 필드를 자유롭게 조작할 수 있습니다.

개요

간단히 말해서, awk에서 레코드는 한 줄을 의미하고, 필드는 그 줄을 구분자로 나눈 각 조각을 의미합니다. 마치 엑셀에서 행(row)과 열(column)의 관계와 같습니다.

왜 이 개념이 중요할까요? 실무에서 다루는 대부분의 텍스트 데이터는 구조화된 형태입니다.

로그 파일, CSV, TSV, 설정 파일 등 모두 필드로 나눌 수 있죠. awk는 이런 구조를 자동으로 인식하고 처리해줍니다.

예를 들어, 특정 사용자의 총 구매 금액을 계산하거나, 에러 타입별 발생 횟수를 집계할 때 매우 유용합니다. 기존에는 프로그래밍 언어로 Dictionary나 HashMap을 직접 만들고 반복문을 작성해야 했다면, 이제는 awk의 연관 배열로 간단하게 처리할 수 있습니다.

코드도 짧아지고 실행 속도도 빠릅니다. awk 필드 처리의 핵심 특징은 세 가지입니다.

첫째, $1, $2처럼 위치로 필드에 접근할 수 있어 직관적입니다. 둘째, NF(필드 개수) 변수로 유연한 처리가 가능합니다.

셋째, 연관 배열로 데이터를 그룹화하고 집계할 수 있습니다. 이러한 특징들이 복잡한 데이터 분석을 놀라울 정도로 간단하게 만들어줍니다.

코드 예제

# 각 필드 출력 (탭으로 구분)
awk '{ print $1, $2, $3 }' data.txt

# 마지막 필드 출력 (NF 사용)
awk '{ print $NF }' file.txt

# 필드 순서 바꾸기
awk '{ print $3, $1, $2 }' data.txt

# 특정 필드만 합계 구하기
awk '{ sum += $2 } END { print "Total:", sum }' numbers.txt

# 연관 배열로 그룹핑 및 집계
awk '{ count[$1]++ } END { for (ip in count) print ip, count[ip] }' access.log

# 필드 개수로 필터링 (필드가 5개인 줄만)
awk 'NF == 5 { print }' data.txt

# 필드 값 수정
awk '{ $2 = $2 * 1.1; print }' prices.txt

설명

이것이 하는 일: awk는 각 줄을 읽을 때마다 자동으로 필드를 분리하고, $1부터 $NF까지 변수에 저장합니다. 여러분은 이 변수들을 사용해서 원하는 연산이나 출력을 수행하면 됩니다.

첫 번째로, $NF는 "마지막 필드"를 의미합니다. NF가 필드 개수이므로, $NF는 그 개수번째 필드가 됩니다.

예를 들어 한 줄에 5개의 필드가 있으면 NF는 5이고, $NF는 $5와 같습니다. 왜 이게 유용할까요?

필드 개수가 일정하지 않은 파일에서 항상 마지막 값을 가져올 수 있기 때문입니다. 그 다음으로, 필드의 순서를 바꾸거나 특정 필드만 선택해서 출력할 수 있습니다.

print $3, $1, $2라고 하면 3번째, 1번째, 2번째 순서로 출력됩니다. 이것은 데이터를 재구성할 때 매우 유용합니다.

쉼표로 구분하면 공백이 들어가고, 쉼표 없이 붙여쓰면 공백 없이 출력됩니다. 세 번째로, 연관 배열(associative array)은 awk의 강력한 기능입니다.

count[$1]++는 "$1의 값을 키로 하는 배열 요소를 1 증가"시킵니다. 예를 들어 IP 주소가 "192.168.1.1"이면 count["192.168.1.1"]이 1씩 증가합니다.

END 블록에서 for (ip in count)로 모든 키를 순회하면서 결과를 출력할 수 있습니다. 마지막으로, 필드 값을 수정할 수도 있습니다.

$2 = $2 * 1.1은 2번째 필드를 1.1배로 만듭니다. 주의할 점은 필드를 수정하면 $0(전체 줄)도 자동으로 재구성된다는 것입니다.

이것은 데이터를 변환할 때 매우 편리합니다. 여러분이 이 기능들을 사용하면 복잡한 로그 분석을 몇 초 만에 완료할 수 있습니다.

예를 들어, 웹 서버 로그에서 IP별 트래픽 분석, URL별 응답 시간 평균, 에러 코드별 발생 빈도 등을 한 줄의 명령어로 처리할 수 있습니다.

실전 팁

💡 연관 배열은 메모리에 저장되므로, 수억 개의 고유 키가 있는 경우 메모리 부족이 발생할 수 있습니다. 큰 파일은 먼저 sort | uniq -c를 사용하는 것도 고려하세요.

💡 필드를 수정한 후 print만 하면 기본 구분자로 재구성됩니다. 원래 형태를 유지하려면 OFS(Output Field Separator)를 원본과 같게 설정하세요.

💡 숫자 계산을 할 때 필드가 비어있으면 0으로 처리되므로 의도치 않은 결과가 나올 수 있습니다. 필요하면 if ($2) sum += $2처럼 검사하세요.

💡 연관 배열을 정렬해서 출력하려면 for (key in array) print key, array[key] | "sort -k2 -n"처럼 파이프로 연결하세요.

💡 필드를 추가하고 싶으면 $(NF+1) = "new_value"처럼 할 수 있습니다. $0이 자동으로 재구성됩니다.


5. awk 패턴과 액션

시작하며

여러분이 서버 로그에서 특정 시간대의 에러만 찾아야 하는 상황을 생각해보세요. "2024"로 시작하고 "ERROR"가 포함된 줄만 추출해서 IP 주소를 세어야 한다면?

이런 복잡한 필터링과 조건부 처리는 데이터 분석의 핵심입니다. 단순히 모든 데이터를 보는 것이 아니라, 원하는 조건에 맞는 것만 골라서 처리해야 효율적이죠.

하지만 여러 조건을 동시에 검사하는 것은 복잡할 수 있습니다. 바로 이럴 때 필요한 것이 awk의 패턴 매칭 기능입니다.

정규표현식, 비교 연산자, 논리 연산자를 조합해서 아주 정교한 필터를 만들 수 있습니다.

개요

간단히 말해서, awk의 패턴은 "어떤 줄을 처리할지" 결정하는 조건이고, 액션은 "선택된 줄로 무엇을 할지" 정의하는 명령입니다. 마치 "if (조건) { 실행 }"과 비슷한 개념입니다.

왜 패턴이 중요할까요? 실무에서는 전체 데이터 중 극히 일부만 필요한 경우가 많습니다.

수백만 줄의 로그 중 에러만, 특정 사용자만, 특정 시간대만 보고 싶을 때가 있죠. awk의 패턴 기능을 사용하면 불필요한 데이터를 효율적으로 걸러낼 수 있습니다.

예를 들어, 응답 시간이 1초 이상인 요청만 추출하거나, 실패한 로그인 시도만 분석할 때 매우 유용합니다. 기존에는 if 문으로 일일이 검사하고 continue로 건너뛰어야 했다면, 이제는 패턴에 조건을 넣으면 자동으로 필터링됩니다.

코드가 깔끔해지고 의도도 명확해집니다. awk 패턴의 핵심 특징은 세 가지입니다.

첫째, 정규표현식 패턴으로 텍스트 매칭을 할 수 있습니다. 둘째, 비교 연산자($3 > 100)로 숫자나 문자열 조건을 검사할 수 있습니다.

셋째, 논리 연산자(&&, ||, !)로 복잡한 조건을 조합할 수 있습니다. 이러한 특징들이 정교한 데이터 필터링을 가능하게 합니다.

코드 예제

# 정규표현식 패턴: ERROR가 포함된 줄만
awk '/ERROR/ { print $1, $3 }' log.txt

# 특정 필드 매칭: 3번째 필드에 "fail"이 있으면
awk '$3 ~ /fail/ { print }' data.txt

# 비교 연산자: 숫자 조건
awk '$2 > 100 { print $1, "is high" }' numbers.txt

# 논리 연산자 AND: 두 조건 모두 만족
awk '$1 == "POST" && $3 > 1000 { print $2 }' access.log

# 논리 연산자 OR: 둘 중 하나만 만족
awk '$2 > 100 || $3 > 200 { print }' data.txt

# 부정 패턴: ERROR가 없는 줄만
awk '!/ERROR/ { print }' log.txt

# 범위 패턴: START부터 END까지
awk '/START/,/END/ { print }' file.txt

# 복합 조건: 패턴 없이 액션 내부에서 if 사용
awk '{ if ($2 > 100 && $1 !~ /test/) print $0 }' data.txt

설명

이것이 하는 일: awk는 각 줄을 읽을 때마다 패턴을 평가하고, 패턴이 참(true)이면 해당 액션을 실행합니다. 패턴이 거짓이면 그 줄은 건너뛰고 다음 줄로 넘어갑니다.

첫 번째로, 정규표현식 패턴 /ERROR/는 줄 전체($0)에서 "ERROR" 문자열을 찾습니다. 대소문자를 구분하므로 "error"는 매칭되지 않습니다.

$3 ~ /fail/처럼 특정 필드만 검사할 수도 있는데, ~는 "매칭된다"는 의미입니다. 반대로 !~는 "매칭되지 않는다"입니다.

그 다음으로, 비교 연산자는 수학적 비교를 수행합니다. $2 > 100은 2번째 필드가 100보다 크면 참입니다.

==는 같다, !=는 다르다, >=는 크거나 같다 등의 연산자를 사용할 수 있습니다. 문자열 비교도 가능한데, 사전식 순서로 비교됩니다.

세 번째로, 논리 연산자로 여러 조건을 결합할 수 있습니다. &&는 AND(둘 다 참), ||는 OR(하나만 참), !는 NOT(부정)입니다.

예를 들어 $1 == "ERROR" && $3 > 100은 "1번째 필드가 ERROR이고 동시에 3번째 필드가 100보다 큰" 줄만 선택합니다. 마지막으로, 범위 패턴 /START/,/END/는 특별한 기능입니다.

START가 나타나면 출력을 시작하고, END가 나타날 때까지 계속 출력합니다. 로그 파일에서 특정 세션이나 구간만 추출할 때 매우 유용합니다.

이것은 상태를 기억하는 방식으로 동작합니다. 여러분이 이 패턴 기능들을 사용하면 복잡한 데이터 필터링을 한 줄로 표현할 수 있습니다.

예를 들어, "응답 시간이 1초 이상이면서 에러 코드가 500인 POST 요청만 보여줘"같은 복잡한 요구사항도 간단하게 처리할 수 있습니다.

실전 팁

💡 정규표현식 패턴은 기본적으로 어디든 매칭되므로, 정확한 매칭이 필요하면 ^(줄 시작), $(줄 끝) 앵커를 사용하세요: /^ERROR/

💡 대소문자 무시 매칭을 하려면 IGNORECASE 변수를 설정하세요: awk 'BEGIN{IGNORECASE=1} /error/ {print}'

💡 문자열과 숫자 비교 시 자동 변환에 주의하세요. "100" > "20"은 거짓입니다(문자열 비교). 숫자로 강제하려면 +0을 더하세요: $2+0 > 100

💡 복잡한 패턴은 가독성을 위해 변수로 빼내세요: awk '{ is_error = ($1 == "ERROR"); if (is_error && $2 > 100) print }'

💡 범위 패턴을 사용할 때 END 패턴이 파일 끝까지 나타나지 않으면 나머지 전체가 출력되므로 주의하세요.


6. 실전 로그 파싱 예제

시작하며

여러분이 프로덕션 서버에서 장애가 발생했다는 연락을 받았다고 상상해보세요. 수십 GB의 로그 파일에서 원인을 빠르게 찾아야 합니다.

어떤 IP에서 가장 많은 에러가 발생했는지, 어떤 시간대에 트래픽이 급증했는지 알아야 하죠. 이런 긴급 상황은 실무에서 정말 자주 발생합니다.

로그 분석 도구를 설치하고 설정할 시간이 없습니다. 빠르게 커맨드라인에서 필요한 정보를 추출해야 합니다.

실수하면 장애 시간이 길어지고 비즈니스에 큰 손실이 발생할 수 있습니다. 바로 이럴 때 필요한 것이 sed와 awk를 조합한 실전 로그 파싱 기술입니다.

복잡한 로그 포맷에서도 원하는 정보를 정확하게 추출하고 분석할 수 있는 실용적인 패턴들을 배워봅시다.

개요

간단히 말해서, 실전 로그 파싱은 sed로 불필요한 부분을 제거하고 awk로 의미 있는 통계를 뽑아내는 과정입니다. 마치 금광에서 흙을 걸러내고 금만 추출하는 것과 비슷합니다.

왜 이 기술이 필수일까요? 실무에서 로그는 모든 문제 해결의 시작점입니다.

애플리케이션 에러, 성능 병목, 보안 침해, 사용자 행동 분석 등 모든 것이 로그에 기록됩니다. 하지만 로그는 양이 방대하고 포맷이 복잡해서 원하는 정보를 찾기 어렵습니다.

sed와 awk를 능숙하게 사용하면 수 GB의 로그를 몇 초 만에 분석할 수 있습니다. 기존에는 로그를 다운로드해서 편집기로 열거나, Python 스크립트를 작성해야 했다면, 이제는 터미널에서 즉시 분석할 수 있습니다.

특히 원격 서버에서 작업할 때 파일을 전송할 필요 없이 바로 분석할 수 있어 시간을 크게 절약합니다. 실전 로그 파싱의 핵심 패턴은 세 가지입니다.

첫째, 에러 추출 및 집계로 문제의 규모를 파악합니다. 둘째, 시간대별 트래픽 분석으로 패턴을 찾습니다.

셋째, 상위 N개 추출로 주요 원인을 식별합니다. 이러한 패턴들이 장애 대응 시간을 수십 배 단축시켜줍니다.

코드 예제

# 1. IP별 요청 횟수 집계 (상위 10개)
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# 2. 시간대별 에러 발생 횟수
awk '/ERROR/ {print substr($1,1,13)}' app.log | sort | uniq -c

# 3. HTTP 상태 코드별 통계
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# 4. 평균 응답 시간 계산
awk '{sum+=$10; count++} END {print "Avg:", sum/count, "ms"}' access.log

# 5. 특정 시간대의 에러만 추출 (sed + awk 조합)
sed -n '/2024-01-15 14:/,/2024-01-15 15:/p' app.log | awk '/ERROR/ {print $3, $5}'

# 6. 가장 느린 요청 10개 찾기
awk '{print $10, $7}' access.log | sort -rn | head -10

# 7. 실패한 로그인 시도 IP 추출
awk '/Failed login/ {print $NF}' auth.log | sort | uniq -c | sort -rn

설명

이것이 하는 일: 이 예제들은 실제 프로덕션 환경에서 가장 자주 사용되는 로그 분석 패턴들입니다. 각각의 명령어는 특정 문제를 진단하기 위해 설계되었습니다.

첫 번째로, IP별 요청 횟수 집계는 DDoS 공격이나 특정 사용자의 과도한 요청을 찾을 때 사용합니다. awk '{print $1}'로 첫 번째 필드(보통 IP 주소)만 추출하고, sort | uniq -c로 중복을 세고, sort -rn으로 내림차순 정렬한 후 head -10으로 상위 10개만 봅니다.

왜 이 순서일까요? sort를 먼저 해야 uniq가 인접한 중복을 셀 수 있기 때문입니다.

그 다음으로, 시간대별 분석은 문제가 언제 발생했는지 파악하는 데 핵심입니다. substr($1,1,13)은 첫 번째 필드에서 앞 13글자만 추출합니다.

"2024-01-15 14:30:25"라면 "2024-01-15 14"만 가져와서 시간대별로 그룹화합니다. 이렇게 하면 특정 시간대에 트래픽이나 에러가 급증했는지 한눈에 볼 수 있습니다.

세 번째로, HTTP 상태 코드 분석은 어떤 종류의 에러가 많은지 파악합니다. $9가 상태 코드 필드라고 가정하면(Apache/Nginx 표준), 200(성공), 404(Not Found), 500(서버 에러) 등의 분포를 볼 수 있습니다.

500번대가 많다면 서버 문제, 400번대가 많다면 클라이언트 문제일 가능성이 높습니다. 네 번째로, 평균 응답 시간 계산은 성능 문제를 찾는 데 사용됩니다.

$10이 응답 시간 필드라면 모든 값을 sum에 더하고, END 블록에서 평균을 계산합니다. 이 값이 급증했다면 데이터베이스 쿼리 느림, 네트워크 지연, CPU 과부하 등을 의심할 수 있습니다.

다섯 번째로, sed와 awk 조합은 특정 시간 범위의 데이터만 분석할 때 유용합니다. sed의 범위 패턴으로 원하는 시간대의 로그만 추출한 후, awk로 에러를 필터링합니다.

이렇게 하면 "14시부터 15시 사이의 에러만 보기"같은 정교한 분석이 가능합니다. 여러분이 이 패턴들을 익히면 장애 상황에서 빠르게 원인을 찾을 수 있습니다.

예를 들어, "갑자기 서버가 느려졌어요"라는 제보를 받으면 즉시 로그를 분석해서 "14:30에 특정 IP에서 초당 1000번 요청을 보냈고, 응답 시간이 평소의 10배로 증가했습니다"같은 구체적인 정보를 제공할 수 있습니다.

실전 팁

💡 대용량 로그는 tail -f로 실시간 모니터링하면서 awk를 사용하세요: tail -f app.log | awk '/ERROR/ {print}'

💡 여러 로그 파일을 동시에 분석할 때는 와일드카드를 사용하세요: awk '{print $1}' access.log.* | sort | uniq -c

💡 복잡한 분석은 파이프로 여러 명령을 연결하되, 중간 결과를 파일로 저장해두면 재분석할 때 빠릅니다: awk ... > temp.txt

💡 로그 포맷이 일정하지 않으면 먼저 head나 tail로 몇 줄을 확인해서 필드 위치를 파악하세요.

💡 성능이 중요하면 불필요한 파이프를 줄이세요. cat file | awk 대신 awk ... file이 더 빠릅니다.


#Linux#sed#awk#TextProcessing#LogParsing#Linux,Bash,Shell

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.