동작하는 코드
예제 1: grep으로 텍스트 검색
먼저 검색할 파일을 준비합니다:
cat Documents/notes.md
출력:
# 메모
- 항목 1
- 항목 2
특정 단어가 포함된 줄 찾기:
grep "항목" Documents/notes.md
출력:
- 항목 1
- 항목 2
줄 번호도 함께 표시:
grep -n "항목" Documents/notes.md
출력:
2:- 항목 1
3:- 항목 2
예제 2: 대소문자 무시 검색
grep -i "hello" Documents/hello.txt
출력:
Hello, World!
-i 옵션은 대소문자를 구분하지 않습니다. Hello, hello, HELLO 모두 검색됩니다.
예제 3: 파이프로 명령어 연결
# ls 출력에서 특정 패턴 필터링
ls | grep ".md"
출력:
notes.md
# 파일 목록의 개수 세기
ls | wc -l
출력:
4
# 3단계 파이프: ls → grep → wc
ls | grep ".txt" | wc -l
출력:
1
직접 수정하기
grep 다양한 옵션
# 여러 파일에서 검색
grep "Hello" Documents/hello.txt Documents/notes.md
# 하위 디렉토리까지 재귀 검색
grep -r "항목" Documents/
# 파일 이름만 출력 (내용 말고)
grep -rl "Hello" .
# 매칭 횟수만 출력
grep -c "항목" Documents/notes.md
출력 예시:
2
# 매칭되지 않는 줄 출력 (역방향 검색)
grep -v "항목" Documents/notes.md
출력:
# 메모
find로 파일 찾기
# 이름으로 파일 찾기
find . -name "*.txt"
출력 예시:
./Documents/hello.txt
./Downloads/readme.txt
# 특정 타입만 (f=파일, d=디렉토리)
find . -type f -name "*.md"
# 최근 1일 이내 수정된 파일
find . -mtime -1
# 특정 크기 이상
find . -size +1k
# 찾은 파일에 명령어 실행 (-exec)
find . -name "*.txt" -exec cat {} \;
"왜?" — 파이프는 왜 강력한가?
파이프(|)는 한 명령어의 stdout을 다음 명령어의 stdin으로 연결합니다.
ls -la | grep ".txt" | wc -l
↓ ↓ ↓
파일 목록 .txt 필터 줄 수 세기
단계별로 보면:
ls -la→ 파일 목록 출력grep ".txt"→.txt가 포함된 줄만 남김wc -l→ 남은 줄 수 세기
결과: 현재 디렉토리의 .txt 파일 개수
파이프의 핵심 원칙: 단순한 도구들을 조합해 복잡한 작업을 처리합니다. 각 명령어는 한 가지 일만 잘 하고, 파이프로 연결해서 복잡한 문제를 해결합니다.
grep 주요 옵션 정리
| 옵션 | 설명 | 예시 |
| ---- | ------------------ | ----------------- |
| -i | 대소문자 무시 | grep -i "hello" |
| -n | 줄 번호 표시 | grep -n "error" |
| -r | 하위 디렉토리 포함 | grep -r "bug" . |
| -l | 파일 이름만 표시 | grep -rl "todo" |
| -v | 매칭 제외 | grep -v "#" |
| -c | 매칭 줄 수만 | grep -c "error" |
실무에서 grep/파이프 활용
# 로그에서 에러만 찾기
cat app.log | grep "ERROR"
# 에러 라인 수 세기
cat app.log | grep "ERROR" | wc -l
# 특정 패턴 제외하고 보기
cat app.log | grep -v "DEBUG"
# 코드에서 특정 함수 찾기
grep -rn "getUserById" src/
흔한 실수
실수 1: grep 패턴에 특수 문자
# . 은 정규식에서 '임의의 문자'를 의미
grep "file.txt" . # file.txt뿐 아니라 file_txt도 매칭됨
# 리터럴로 찾으려면 이스케이프
grep "file\.txt" .
# 또는 -F (고정 문자열)
grep -F "file.txt" .
실수 2: -r 없이 디렉토리 검색
grep "텍스트" Documents/ # 에러
# grep: Documents/: Is a directory
grep -r "텍스트" Documents/ # 올바름
실수 3: find 결과를 grep으로 전달하기
# 잘못된 방법: 파일 내용이 아닌 파일명에서 grep
find . -name "*.txt" | grep "hello" # 파일명에 "hello"가 있는 것만 찾음
# 올바른 방법: 파일 내용 검색
grep -r "hello" --include="*.txt" .
심화 학습
정규식(regex)으로 패턴 검색
grep은 정규식을 지원합니다:
# ^ : 줄 시작
grep "^-" Documents/notes.md
# $ : 줄 끝
grep "2$" Documents/notes.md
# . : 임의의 문자 하나
grep "항.1" Documents/notes.md
# []: 문자 집합 중 하나
grep "[12]" Documents/notes.md
# 확장 정규식 (-E)
grep -E "항목 [12]" Documents/notes.md
정규식은 강력하지만 처음에는 어렵습니다. 기본 옵션만으로도 대부분의 검색이 가능하니 필요할 때 배워도 됩니다.
find의 강력한 -exec 옵션
찾은 파일에 직접 명령어를 실행합니다:
# 모든 .log 파일 삭제
find . -name "*.log" -exec rm {} \;
# 모든 .txt 파일 내용 출력
find . -name "*.txt" -exec cat {} \;
# 찾은 파일 목록을 파일로 저장 (리다이렉션 사용)
find . -name "*.md" > md-files.txt
{}는 찾은 파일 경로로 치환되고, \;는 명령어의 끝을 나타냅니다.
grep 대신 ripgrep(rg) 쓰는 이유
개발자들 사이에서는 rg(ripgrep)을 많이 씁니다:
brew install ripgrep
# 일반 사용 (grep -r과 유사)
rg "함수명" src/
# .gitignore 자동으로 무시
# 색상 출력 기본 지원
# grep보다 수십 배 빠름
대용량 코드베이스(수만 개 파일)에서 특히 효과적입니다. VS Code의 전체 검색도 내부적으로 ripgrep을 씁니다.
grep "Hello" Documents/hello.txt로 파일에서 텍스트를 검색하세요.grep -n "항목" Documents/notes.md로 줄 번호와 함께 검색하세요.grep -c "항목" Documents/notes.md로 매칭된 줄 수를 세세요.ls | grep ".txt"로 현재 가상 파일시스템에서 .txt 파일만 나열하세요.grep -r "Hello" .으로 현재 디렉토리 전체에서 "Hello"를 검색하세요.
Q1. ls | grep ".txt" | wc -l 이 명령어가 출력하는 것은?
- A) .txt 파일의 내용
- B) 현재 디렉토리에서 이름에 ".txt"가 포함된 항목의 수
- C) .txt 파일의 총 크기
- D) .txt 파일의 목록