Linux 'grep'

개요

grep은 파일, 디렉토리, 스트림을 가로질러 패턴에 맞는 줄을 걸러내는 가장 빠른 방법이다. 이 글은 GNU grep 기준이며 실무에서 바로 쓸 수 있는 예제 위주다.

요약 (치트시트)

  • 기본: grep PATTERN file
  • 대소문자 무시: -i
  • 줄 번호: -n
  • 개수만: -c
  • 파일명만: -l (반대는 -L)
  • 매칭된 부분만: -o
  • 확장 정규식: -E
  • 고정 문자열 (정규식 아님, 더 빠름): -F
  • 매칭 반전: -v
  • 재귀: -r (심볼릭 링크 무시), -R (심볼릭 링크 따라감)
  • 문맥: -B N, -A N, -C N
  • 포함/제외 glob: --include, --exclude, --exclude-dir
  • 색상: --color=auto (강제는 --color=always)
  • 바이너리 건너뛰기: -I
  • NUL 안전 파이핑: -Z (xargs -0와 함께)

실제로 쓰게 되는 핵심 패턴

# 파일 필터를 건 재귀 검색
grep -Rni --include='*.log' --exclude-dir='.git' 'ERROR' .

# 파일별 매칭 개수 (CI에서 빠르게 신호 얻기)
grep -Rc --include='*.py' 'TODO' src/

# 매칭된 부분만 출력 (예: 저널의 HTTP 상태 코드)
journalctl -u nginx | grep -oE 'status=[0-9]{3}'

# 단어 경계 검색 (과도한 매칭 방지)
grep -rw --include='*.c' '\<init\>' src/

# 리터럴 텍스트 (빠르고, 정규식 메타문자를 무시)
grep -F '[INFO]' app.log

# 이상한 파일명(공백/개행)에도 안전하게
find . -name '*.md' -print0 | xargs -0 grep -n 'architecture'

실제로 중요한 성능 요령

  • 리터럴 패턴에는 -F 를 쓴다 (보통 훨씬 빠르다).
  • 거대한 입력에서 바이트 단위 매칭과 속도를 원하면 LC_ALL=C 를 쓴다:

    LC_ALL=C grep -rF 'needle' /data/terabytes
    
  • -I 또는 --binary-files=without-match로 바이너리를 건너뛴다.
  • 처음 N개만 필요하면 -m N으로 일찍 멈춘다.
  • 지연 시간이 중요한 파이프라인에서는 --line-buffered를 지원하는 도구도 있다. GNU grep은 줄 끝에서 자동으로 플러시하지만, 파이프라인 전체의 버퍼링은 여전히 적용된다.

정규식 최소 지식

  • -E (ERE): foo|bar, a{2,5}, colou?r, (ba|be)z.
  • 룩어라운드가 필요하면 -P (PCRE):

    grep -Po '(?<=user=)[^ &]+' access.log
    

    참고: 기본 BSD/macOS grep에는 -P가 없을 수 있다. GNU grep(예: Homebrew의 ggrep)을 쓰거나 awk/sed로 바꿔 쓰자.

문맥과 보고

# 주변 줄 함께 보기 (앞뒤 2줄)
grep -nC2 'panic' kernel.log

# 매칭이 있는 파일명만
grep -Rl 'TODO' src/

# 파일명 숨기기 (여러 파일, 줄만)
grep -h 'pattern' file1 file2

실무 미니 쿡북

# 1) 매칭 주변 문맥과 함께 에러 폭주 요약
grep -Rni --include='*.log' 'CRITICAL' logs/ | sed -n 's/:.*//p' | sort -u \
 | xargs -I{} sh -c "echo '--- {} ---'; grep -nC2 'CRITICAL' {}"

# 2) JSON 값 추출 (단순한 경우)
grep -Po '"user_id"\s*:\s*"\K[^"]+' events.jsonl | sort | uniq -c | sort -nr | head

# 3) 매칭되지 '않는' 줄 찾기 (예: 헬스체크 제외)
grep -R 'GET /' access.log | grep -v '/healthz'

플랫폼 차이

  • GNU vs BSD (macOS) 차이:

    • BSD grep에는 -P가 없는 경우가 많다.
    • 일부 롱 옵션이 다르다. 항상 man grep을 확인하자.
    • PCRE가 필요하거나 동작을 일관되게 유지하려면 GNU grep을 설치한다.

흔한 함정 (과 해법)

  • 리터럴을 원했는데 정규식으로 해석됨 → -F를 쓴다.
  • 로케일로 인한 의외의 동작 / 거대 입력에서의 저성능 → LC_ALL=C.
  • 재귀 검색이 느림 → --include/--exclude로 범위를 좁히고 -F를 선호한다.
  • cat의 무의미한 사용 → grep pattern file (필요할 때만 파이프).