ripgrep(rg) 사용법: grep보다 빠르고 스마트한 검색 도구

ripgrep(rg) 사용법: grep보다 빠르고 스마트한 검색 도구

이전 글에서 grep의 기본기를 살펴봤는데요. grep이 50년 넘게 살아남은 검증된 도구인 건 맞지만, 요즘 코드베이스를 다루다 보면 살짝 아쉬운 부분이 있습니다. node_modules를 빼먹으면 결과가 쏟아지고, .gitignore에 있는 파일까지 뒤지고, 바이너리 파일도 가리지 않죠 😅

ripgrep(rg)은 이런 불편함을 해결하기 위해 만들어진 검색 도구입니다. fd의 핵심 라이브러리를 만든 Andrew Gallant(BurntSushi)가 Rust로 개발했고, grep보다 훨씬 빠르면서도 개발자에게 친화적인 기본값을 가지고 있어요. fdfind의 현대적 대안이라면, ripgrepgrep의 현대적 대안인 셈이죠.

이번 글에서는 ripgrep의 설치부터 핵심 기능, 그리고 실전에서 자주 쓰는 패턴까지 살펴보겠습니다.

설치

macOS에서는 Homebrew로 간단하게 설치할 수 있습니다.

brew install ripgrep

Linux(Debian/Ubuntu)에서는 apt로 설치합니다.

sudo apt-get install ripgrep

Windows에서는 Chocolatey나 Scoop을 사용하면 됩니다.

choco install ripgrep
# 또는
scoop install ripgrep

Rust 개발 환경이 갖춰져 있다면 Cargo로도 설치할 수 있어요.

cargo install ripgrep

설치가 끝나면 rg --version으로 확인해봅니다.

rg --version
결과
ripgrep 14.1.1

기본 사용법

가장 기본적인 형태는 rg 패턴입니다. 현재 디렉토리에서 재귀적으로 검색하죠. grep처럼 -r 옵션을 따로 붙일 필요가 없어요.

rg "getPublishedPosts" src/
결과
src/pages/[slug].astro:  getPublishedPosts,
src/pages/[slug].astro:  const posts = await getPublishedPosts();
src/pages/index.astro:  getPublishedPosts,
src/pages/index.astro:const posts = await getPublishedPosts();
src/layouts/BaseLayout.astro:import { getPublishedPosts, getAllTags, getTagCounts } from "../utils/posts";
src/layouts/BaseLayout.astro:const posts = await getPublishedPosts();

grep으로 같은 검색을 하려면 grep -rn "getPublishedPosts" src/ --exclude-dir=node_modules처럼 꽤 긴 명령어가 필요한데, rg는 그냥 패턴과 경로만 주면 됩니다. .gitignore에 등록된 디렉토리는 자동으로 건너뛰거든요.

줄 번호를 함께 보려면 -n 옵션을 붙입니다.

rg -n "function" src/utils/ -t ts
결과
src/utils/posts.ts:22:export async function getPublishedPosts() {
src/utils/posts.ts:33:export function getAllTags(post: { data: { tags: string[] } }): string[] {
src/utils/posts.ts:38:export function getPostsByTag(
src/utils/posts.ts:56:export function getTagCounts(
src/utils/posts.ts:71:export function getRelatedPosts(
src/utils/tags.ts:16:function toTagId(tag: string): string {
src/utils/tags.ts:23:function buildTagLookup(tagEntries: TagEntry[]): Map<string, TagEntry> {
src/utils/tags.ts:33:export function getTopTags(
src/utils/korean.ts:9:export function hasKorean(text: string): boolean {

grep과 뭐가 다를까

ripgrepgrep과 가장 크게 다른 점은 스마트한 기본값입니다.

우선 .gitignore를 자동으로 존중합니다. node_modules, dist, .next 같은 디렉토리가 .gitignore에 있으면 검색 대상에서 알아서 빠져요. grep에서 매번 --exclude-dir을 붙이던 수고를 덜 수 있죠. 숨김 파일(.env, .git)도 기본적으로 건너뛰고, 바이너리 파일도 자동으로 무시합니다.

이 기본값을 단계적으로 해제할 수도 있습니다. -u 플래그를 하나씩 추가할 때마다 필터가 하나씩 풀려요.

rg -u "pattern"     # .gitignore 무시
rg -uu "pattern"    # .gitignore + 숨김 파일 무시
rg -uuu "pattern"   # 모든 필터 해제 (grep -r과 동일)

-uuu까지 붙이면 grep -r과 거의 동일하게 동작합니다. 디버깅할 때 “혹시 .gitignore 때문에 결과에서 빠진 건 아닐까?” 싶을 때 유용해요.

또한 출력이 터미널일 때 자동으로 색상을 입혀주고, 파일명과 줄 번호를 보기 좋게 정렬해줍니다. grep에서 --color=auto를 붙이는 걸 깜빡할 일이 없어요.

파일 타입 필터링

grep에서 특정 확장자만 검색하려면 --include="*.ts" 옵션을 써야 하는데, ripgrep-t 플래그로 파일 타입을 지정합니다.

rg "function" src/utils/ -t ts

-t ts라고 쓰면 .ts.tsx 파일을 모두 검색합니다. ripgrep이 각 타입에 어떤 확장자가 포함되는지 미리 알고 있거든요. 지원하는 타입 목록은 --type-list로 확인할 수 있습니다.

rg --type-list | head -5
결과
ada: *.adb, *.ads
agda: *.agda, *.lagda
aidl: *.aidl
alire: alire.toml
amake: *.bp, *.mk

100개가 넘는 타입이 미리 정의되어 있어요. 자주 쓰는 것만 정리하면 이렇습니다.

  • js*.js, *.mjs, *.cjs
  • ts*.ts, *.tsx
  • py*.py, *.pyi
  • rust*.rs
  • css*.css, *.scss
  • html*.htm, *.html
  • json*.json
  • md*.md, *.markdown
  • yaml*.yaml, *.yml

반대로 특정 타입을 제외하고 싶으면 -T(대문자)를 씁니다.

rg "config" src/ -T json -T yaml

JSON과 YAML 파일을 제외하고 검색하겠다는 뜻이에요.

미리 정의되지 않은 파일 타입은 --type-add로 추가할 수 있습니다. 예를 들어 이 블로그 프로젝트에서 쓰는 .astro 파일은 기본 타입 목록에 없는데, 이렇게 추가하면 됩니다.

rg --type-add "astro:*.astro" -t astro "getPublishedPosts" src/

매번 --type-add를 붙이기 번거로우면 뒤에서 소개할 설정 파일에 등록해두면 됩니다.

글로브 패턴

파일 타입 대신 글로브 패턴으로 검색 대상을 제어할 수도 있습니다. -g(또는 --glob) 옵션을 쓰면 돼요.

# .astro 파일만 검색
rg -g "*.astro" "getPublishedPosts" src/

# 테스트 파일 제외
rg -g "!*.spec.ts" "function" src/

# 특정 디렉토리의 특정 확장자만
rg -g "src/utils/*.ts" "export"

!를 붙이면 해당 패턴을 제외한다는 뜻입니다. -t로 커버되지 않는 세밀한 필터링이 필요할 때 유용합니다.

정규표현식

ripgrep은 기본적으로 Rust의 정규표현식 엔진을 사용합니다. grep -E(확장 정규표현식)와 비슷하지만 기본값이라 별도 옵션이 필요 없어요.

rg "^(import|export)" src/utils/posts.ts
결과
import { getCollection, type CollectionEntry } from "astro:content";
import type { ImageMetadata } from "astro";
import { remark } from "remark";
import strip from "strip-markdown";
import { extractLocalImageFilename } from "./og";
import { getGroupTagMap, getTagImage } from "./tags";
export async function getPublishedPosts() {
export function getAllTags(post: { data: { tags: string[] } }): string[] {
export function getPostsByTag(
export function getTagCounts(
export function getRelatedPosts(
export interface PostSummary {
export async function sortAndMapPosts(
export function hasBodyMedia(body: string): boolean {
export async function getExcerpt(

단어 경계 매칭도 grep과 동일하게 -w 옵션을 지원합니다.

rg -w "post" src/utils/posts.ts

post만 매칭하고 posts, getPost, PostSummary 같은 건 잡지 않습니다.

Lookahead나 Backreference 같은 고급 기능이 필요하면 -P 옵션으로 PCRE2 엔진을 활성화할 수 있습니다. 빌드할 때 PCRE2를 포함시켜야 하는데, 대부분의 패키지 매니저로 설치하면 이미 포함되어 있어요.

# 뒤에 괄호가 오지 않는 function 찾기 (negative lookahead)
rg -P "function\s+\w+(?!\()" src/utils/

맥락 보기와 카운팅

grep과 동일하게 -A, -B, -C 옵션으로 매칭된 줄 주변의 맥락을 볼 수 있습니다.

rg -B 2 -A 2 "getPublishedPosts" src/utils/posts.ts
결과
 * In development (DEV mode), drafts are included for preview.
 */
export async function getPublishedPosts() {
  const posts = await getCollection("posts", ({ data }) => {
    // In development, show all posts including drafts

파일별 매칭 횟수를 보려면 -c 옵션을 씁니다.

rg -c "import" src/utils/ -t ts
결과
src/utils/posts.ts:8
src/utils/og.ts:5
src/utils/tags.ts:3

전체 검색 통계가 궁금하면 --stats 옵션이 유용합니다.

rg --stats "function" src/utils/ -t ts -q
결과
23 matches
23 matched lines
4 files contained matches
4 files searched
0 bytes printed
13640 bytes searched
0.000031 seconds spent searching
0.002370 seconds

13KB를 검색하는 데 0.002초 걸렸네요. 작은 프로젝트라 체감이 안 될 수 있지만, 리눅스 커널처럼 수만 개의 파일이 있는 프로젝트에서는 grep과 차이가 확 벌어집니다.

멀티 패턴 검색

여러 패턴을 동시에 검색하려면 -e 옵션을 반복하면 됩니다.

rg -e "TODO" -e "FIXME" -e "HACK" src/

grep에서도 -e를 쓸 수 있지만, ripgrep.gitignore를 알아서 처리하니까 node_modules 안의 TODO까지 잔뜩 나오는 일이 없어서 결과가 훨씬 깔끔합니다.

파일 목록만 보기

매칭된 내용은 필요 없고 어떤 파일에 패턴이 있는지만 알고 싶을 때는 -l 옵션을 씁니다.

rg -l "dark-mode" src/

반대로 패턴이 없는 파일 목록이 필요하면 --files-without-match를 쓰면 돼요.

rg --files-without-match "export" src/utils/ -t ts

JSON 출력

검색 결과를 다른 도구로 파이핑하거나 프로그래밍 방식으로 처리할 때 --json 옵션이 편합니다.

rg --json "function" src/utils/korean.ts

각 매칭 결과가 JSON 한 줄로 나오는데, 파일 경로, 줄 번호, 매칭된 범위, 줄 내용이 구조화되어 있어서 jq로 가공하기 좋아요.

설정 파일

ripgrepRIPGREP_CONFIG_PATH 환경 변수로 지정한 설정 파일에서 기본 옵션을 읽어옵니다. 매번 명령줄에 타이핑하던 옵션을 파일로 빼두면 편하겠죠.

export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

설정 파일은 한 줄에 옵션 하나씩 쓰는 방식입니다.

.ripgreprc
# 스마트 케이스: 패턴이 소문자만이면 대소문자 무시
--smart-case

# 커스텀 파일 타입 추가
--type-add=astro:*.astro
--type-add=svelte:*.svelte
--type-add=vue:*.vue

# 숨김 파일도 검색
--hidden

# .git 디렉토리는 제외
--glob=!.git/

--smart-case는 특히 추천하는 옵션입니다. 패턴이 전부 소문자면 대소문자를 무시하고, 대문자가 하나라도 있으면 정확히 매칭해요. rg "function"Function, FUNCTION도 잡고, rg "Function"은 정확히 Function만 잡는 거죠. grep에서 -i를 붙였다 뺐다 하는 번거로움이 사라집니다.

실전 활용 패턴

지금까지 살펴본 기능을 조합하면 개발하면서 자주 마주치는 상황을 꽤 효율적으로 처리할 수 있습니다.

# 프로젝트에서 특정 함수가 어디서 쓰이는지 찾기
rg "getPublishedPosts" src/ -t ts -g "*.astro"

# 특정 파일의 import/export 구조 파악
rg "^(import|export)" src/utils/posts.ts

# 파일별 매칭 수로 가장 복잡한 파일 찾기
rg -c "if|else|switch|for|while" src/ -t ts --sort-files

# .env 파일에서 특정 키 찾기 (숨김 파일 포함)
rg --hidden "DATABASE_URL" -g ".env*"

# 마크다운 파일에서 깨진 링크 후보 찾기
rg "\[.*\]\(\)" src/content/posts/ -t md

# 특정 패턴이 없는 파일 찾기 (description 누락 등)
rg --files-without-match "^description:" src/content/posts/ -t md

코딩 에이전트와 ripgrep

요즘 코딩 에이전트들이 코드를 검색할 때 ripgrep을 적극적으로 사용합니다. 클로드 코드(Claude Code)의 내장 Grep 도구도 ripgrep을 기반으로 동작하고, VS Code도 파일 검색에 ripgrep을 쓰고 있어요.

그 이유는 분명합니다. .gitignore를 자동으로 존중하니까 불필요한 검색 결과가 없고, 속도가 빨라서 대규모 코드베이스에서도 응답 시간이 짧거든요. 에이전트가 수십 번의 검색을 연달아 수행해야 하는 상황에서 이 차이는 꽤 크게 작용합니다.

마치며

ripgrepgrep의 핵심 기능을 그대로 가져오면서 개발자에게 필요한 기본값을 잘 갖춘 도구입니다. .gitignore 자동 적용, 파일 타입 필터링, 빠른 속도까지 — 한번 쓰기 시작하면 다시 grep으로 돌아가기 어려워요.

그렇다고 grep을 완전히 잊어도 된다는 건 아닙니다. grep은 거의 모든 시스템에 기본 설치되어 있으니까, 원격 서버에 SSH로 접속했거나 최소한의 Docker 컨테이너 안에서 작업할 때는 여전히 grep이 필요합니다. 로컬 개발 환경에서는 ripgrep, 서버 환경에서는 grep — 이렇게 상황에 맞게 쓰는 게 가장 현실적이에요.

더 자세한 내용은 ripgrep 공식 저장소를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord