grep으로 패턴 검색
서버가 갑자기 느려졌습니다. 원인을 찾으려면 로그 파일을 뒤져야 하는데, 파일이 수만 줄입니다. 전부 읽을 수는 없습니다. 이럴 때 grep이 필요합니다.
grep은 파일이나 표준 입력에서 특정 패턴이 있는 줄만 골라냅니다. 이름은 "global regular expression print"의 약자입니다. 단순히 문자열을 찾는 것 같지만, 옵션을 조합하면 로그 분석, 코드 검색, 데이터 필터링까지 처리합니다.
기본 사용법
grep "패턴" 파일명grep "패턴" 파일1 파일2grep "패턴" # 표준 입력에서 검색 (Ctrl+D로 종료)
먼저 실습에 쓸 샘플 로그 파일을 만들겠습니다.
# 새 파일: /tmp/access.logcat > /tmp/access.log << 'EOF'192.168.1.1 - - [24/Apr/2026:09:01:00 +0900] "GET /index.html HTTP/1.1" 200 1234192.168.1.2 - - [24/Apr/2026:09:01:05 +0900] "POST /login HTTP/1.1" 401 51210.0.0.5 - - [24/Apr/2026:09:01:10 +0900] "GET /api/users HTTP/1.1" 200 4096192.168.1.1 - - [24/Apr/2026:09:01:15 +0900] "GET /admin HTTP/1.1" 403 25610.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128192.168.1.3 - - [24/Apr/2026:09:01:25 +0900] "GET /index.html HTTP/1.1" 200 123410.0.0.5 - - [24/Apr/2026:09:01:30 +0900] "GET /api/items HTTP/1.1" 200 2048192.168.1.2 - - [24/Apr/2026:09:01:35 +0900] "POST /login HTTP/1.1" 200 768192.168.1.4 - - [24/Apr/2026:09:01:40 +0900] "GET /notfound HTTP/1.1" 404 6410.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128EOF
기본 검색을 해봅니다.
grep "500" /tmp/access.log
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
HTTP 상태 코드 500인 줄만 나왔습니다.
자주 쓰는 옵션
| 옵션 | 설명 | 예시 |
|---|---|---|
-i |
대소문자 구분 없이 검색 | grep -i "error" log.txt |
-n |
줄 번호 함께 출력 | grep -n "error" log.txt |
-c |
일치하는 줄 수만 출력 | grep -c "200" access.log |
-v |
패턴과 일치하지 않는 줄 출력 | grep -v "200" access.log |
-r |
디렉토리를 재귀적으로 검색 | grep -r "TODO" ./src |
-l |
패턴이 있는 파일명만 출력 | grep -rl "error" ./logs |
-w |
단어 단위로 검색 | grep -w "log" log.txt |
-A N |
일치 줄 아래 N줄도 출력 | grep -A 2 "500" access.log |
-B N |
일치 줄 위 N줄도 출력 | grep -B 2 "500" access.log |
-C N |
일치 줄 위아래 N줄 출력 | grep -C 1 "500" access.log |
각 옵션을 직접 확인합니다.
# 줄 번호와 함께 출력grep -n "500" /tmp/access.log
5:10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
10:10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
# 500이 없는 줄만 출력 (정상 응답)grep -v "500" /tmp/access.log | grep -v "401" | grep -v "403" | grep -v "404"
192.168.1.1 - - [24/Apr/2026:09:01:00 +0900] "GET /index.html HTTP/1.1" 200 1234
10.0.0.5 - - [24/Apr/2026:09:01:10 +0900] "GET /api/users HTTP/1.1" 200 4096
192.168.1.3 - - [24/Apr/2026:09:01:25 +0900] "GET /index.html HTTP/1.1" 200 1234
10.0.0.5 - - [24/Apr/2026:09:01:30 +0900] "GET /api/items HTTP/1.1" 200 2048
192.168.1.2 - - [24/Apr/2026:09:01:35 +0900] "POST /login HTTP/1.1" 200 768
# 500 오류 전후 2줄도 함께 출력 (맥락 파악)grep -C 2 "500" /tmp/access.log
10.0.0.5 - - [24/Apr/2026:09:01:10 +0900] "GET /api/users HTTP/1.1" 200 4096
192.168.1.1 - - [24/Apr/2026:09:01:15 +0900] "GET /admin HTTP/1.1" 403 256
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
192.168.1.3 - - [24/Apr/2026:09:01:25 +0900] "GET /index.html HTTP/1.1" 200 1234
10.0.0.5 - - [24/Apr/2026:09:01:30 +0900] "GET /api/items HTTP/1.1" 200 2048
--
10.0.0.5 - - [24/Apr/2026:09:01:30 +0900] "GET /api/items HTTP/1.1" 200 2048
192.168.1.2 - - [24/Apr/2026:09:01:35 +0900] "POST /login HTTP/1.1" 200 768
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
--는 두 개의 일치 구간 사이를 구분하는 구분자입니다.
여러 패턴 검색
한 번에 여러 패턴을 찾으려면 -E 옵션과 |를 사용합니다.
# 500 또는 404 오류 찾기grep -E "500|404" /tmp/access.log
192.168.1.4 - - [24/Apr/2026:09:01:40 +0900] "GET /notfound HTTP/1.1" 404 64
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
패턴이 많으면 파일에 저장해서 사용할 수 있습니다.
# 패턴 파일 만들기cat > /tmp/error_patterns.txt << 'EOF'401403404500EOF# 파일에서 패턴 읽기grep -f /tmp/error_patterns.txt /tmp/access.log
192.168.1.2 - - [24/Apr/2026:09:01:05 +0900] "POST /login HTTP/1.1" 401 512
192.168.1.1 - - [24/Apr/2026:09:01:15 +0900] "GET /admin HTTP/1.1" 403 256
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
192.168.1.4 - - [24/Apr/2026:09:01:40 +0900] "GET /notfound HTTP/1.1" 404 64
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
파이프와 조합
grep은 파이프와 함께 쓸 때 진짜 힘이 납니다.
# 실행 중인 프로세스에서 nginx만 찾기ps aux | grep nginx | grep -v grep
# 현재 디렉토리 아래 모든 .sh 파일에서 TODO 찾기grep -rn "TODO" /tmp --include="*.sh"
# 오류 줄이 몇 개인지 세기grep -c "500" /tmp/access.log
2
# 오류 상태 코드 목록 중 어떤 파일에 있는지 파일명만 출력grep -rl "500" /tmp/
/tmp/access.log
실습: 로그 분석 파이프라인
실무에서 자주 쓰이는 패턴을 연습합니다.
# 실습 1: 오늘 발생한 오류 줄만 추출grep -E "40[0-9]|5[0-9]{2}" /tmp/access.log
192.168.1.2 - - [24/Apr/2026:09:01:05 +0900] "POST /login HTTP/1.1" 401 512
192.168.1.1 - - [24/Apr/2026:09:01:15 +0900] "GET /admin HTTP/1.1" 403 256
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
192.168.1.4 - - [24/Apr/2026:09:01:40 +0900] "GET /notfound HTTP/1.1" 404 64
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
# 실습 2: 소스 코드 전체에서 TODO 주석 찾기 (파일명 + 줄 번호 포함)grep -rn "TODO\|FIXME\|HACK" /tmp --include="*.sh" 2>/dev/null || echo "검색 결과 없음"
# 실습 3: 특정 IP의 요청만 추출grep "10.0.0.5" /tmp/access.log
10.0.0.5 - - [24/Apr/2026:09:01:10 +0900] "GET /api/users HTTP/1.1" 200 4096
10.0.0.5 - - [24/Apr/2026:09:01:20 +0900] "DELETE /api/users/3 HTTP/1.1" 500 128
10.0.0.5 - - [24/Apr/2026:09:01:30 +0900] "GET /api/items HTTP/1.1" 200 2048
10.0.0.5 - - [24/Apr/2026:09:01:45 +0900] "GET /api/users HTTP/1.1" 500 128
-w 옵션으로 단어 단위 검색을 주의해서 써야 할 때가 있습니다. grep "10" access.log는 IP에서 10이 들어가는 모든 줄을 잡지만, grep -w "10" access.log는 단독 단어 "10"이 있는 줄만 잡습니다. IP 검색처럼 더 정밀한 패턴이 필요한 경우는 02장에서 정규표현식으로 처리합니다.