find: 디렉터리 트리를 순회하며 조건에 맞는 파일을 찾는 명령어
find는 지정한 디렉터리부터 하위 트리를 재귀적으로 순회하면서 이름, 크기, 수정 시각, 타입 같은 조건에 맞는 파일을 찾아 주는 리눅스 명령어다. 조건식(expression)을 왼쪽에서 오른쪽으로 평가하고, 일치한 항목에 대해 출력이나 삭제, 명령 실행 같은 동작(action)을 수행한다. 기본 사용법과 실무에서 자주 쓰는 패턴, 공백 파일명 처리 같은
By 송민성
1. 개념
find는 시작 경로(starting point)부터 디렉터리 트리를 재귀적으로 순회하면서, 각 파일과 디렉터리에 조건식(expression)을 적용하는 명령어다. 기본 형태는 다음과 같다.
find [시작경로...] [표현식]표현식은 세 종류의 요소로 구성된다.
- 테스트(test): 조건을 검사해 참/거짓을 반환한다. 예:
-name,-type,-size,-mtime - 액션(action): 일치한 항목에 수행할 동작이다. 예:
-print,-delete,-exec - 연산자(operator): 조건을 조합한다. 예:
-and(-a),-or(-o),!(NOT),\( \)(그룹)
2. 왜 사용하는가
ls나 셸 글롭(glob,*.log)은 현재 디렉터리 수준에서 이름 패턴만 다루기 쉽다.find는 깊이에 상관없이 하위 전체를 대상으로 한다.- 이름뿐 아니라 파일 타입, 크기, 수정 시각, 소유자, 권한 같은 메타데이터로 검색할 수 있다.
- 찾은 결과에 바로 삭제, 권한 변경, 다른 명령 실행을 연결할 수 있어 정리·점검 스크립트의 기본 도구가 된다.
3. 동작 원리
- 시작 경로를 연다.
- 디렉터리 엔트리를 하나씩 읽으며 각 항목의 메타데이터(
stat정보)를 필요할 때 조회한다. - 항목이 디렉터리면 그 안으로 내려가 같은 과정을 반복한다(깊이 우선 순회).
- 각 항목에 대해 표현식을 왼쪽에서 오른쪽으로 평가한다.
-and가 기본 연산자이므로 조건을 나열하면 모두 만족해야 한다. 앞의 조건이 거짓이면 뒤의 조건은 평가하지 않는다(단락 평가, short-circuit). - 표현식에 액션이 하나도 없으면
-print가 암묵적으로 적용된다.
그래서 조건의 순서가 결과와 성능에 영향을 줄 수 있다. 특히 -delete나 -exec 같은 액션은 앞의 조건이 참일 때만 실행되므로, 액션은 조건 뒤에 둬야 한다.
주요 테스트는 다음과 같다.
| 옵션 | 의미 |
|---|---|
| -name 'PATTERN' | 파일명이 글롭 패턴과 일치 (대소문자 구분) |
| -iname 'PATTERN' | 대소문자 무시 |
| -type f / d / l | 일반 파일 / 디렉터리 / 심볼릭 링크 |
| -size +10M | 10MiB 단위 기준 초과 (k, M, G 단위 사용) |
| -mtime -1 | 수정된 지 24시간 이내 |
| -mtime +7 | 수정된 지 7일을 초과 |
| -maxdepth N | 최대 N단계 깊이까지만 탐색 (GNU/BSD 모두 지원) |
| -perm MODE | 권한 비교 |
| -user NAME | 소유자 |
-size의 M은 GNU find 기준 1048576바이트(MiB) 단위로 올림하여 비교한다. -mtime은 24시간 단위로 내림하여 계산하므로 -mtime +7은 "8일 이상 지난" 파일을 뜻한다.
4. 코드 예제
실습용 디렉터리를 만들고 find를 실행해 보자.
# 실습 환경 준비
mkdir -p /tmp/find-demo/src/utils /tmp/find-demo/logs
cd /tmp/find-demo
echo "console.log(1)" > src/app.js
echo "export {}" > src/utils/helper.ts
echo "error" > logs/app.log
echo "old" > logs/old.log
echo "공백" > "my file.txt"
touch -d '10 days ago' logs/old.log # GNU touch 기준. macOS는 touch -t 사용
# 1) 이름으로 찾기
find . -name '*.log'
# 2) 파일만, 확장자 두 종류 (그룹 괄호는 이스케이프)
find . -type f \( -name '*.js' -o -name '*.ts' \)
# 3) 깊이 제한
find . -maxdepth 1 -type f
# 4) 7일보다 오래된 로그 찾기
find logs -type f -name '*.log' -mtime +7
# 5) 찾은 파일에 명령 실행 (+ 는 인자를 묶어 한 번에 전달)
find . -type f -name '*.js' -exec grep -l 'console' {} +
# 6) 안전하게 삭제: 먼저 -print로 확인한 뒤 -delete
find logs -type f -name '*.log' -mtime +7 -print
find logs -type f -name '*.log' -mtime +7 -delete
# 7) 공백이 들어간 파일명을 안전하게 파이프로 전달
find . -type f -name '*.txt' -print0 | xargs -0 wc -c
# 8) node_modules 제외하고 탐색
find . -name node_modules -prune -o -type f -name '*.js' -print8번에서 -prune은 해당 디렉터리로 내려가지 않게 하며, 뒤에 -print를 명시해야 제외한 항목이 출력되지 않는다.
5. 시간 복잡도 또는 성능 특성
- find는 인덱스를 쓰지 않고 실제 파일시스템을 순회하므로, 비용은 방문하는 항목 수 N에 비례한다. 즉 O(N)이다.
- 실제 시간은 디스크 I/O, 디렉터리 캐시(dentry cache) 상태, 네트워크 파일시스템 여부에 크게 좌우된다.
-name처럼 이름만 보는 테스트는 추가stat호출이 필요 없는 경우가 많고,-size·-mtime같은 테스트는 메타데이터 조회가 필요하다.-exec cmd {} \;는 파일마다 프로세스를 새로 띄우고,-exec cmd {} +는 인자를 묶어 호출 횟수를 줄인다. 대상이 많으면+가 일반적으로 훨씬 유리하다.- 대안으로
locate는 미리 만든 데이터베이스를 조회해 빠르지만, 데이터베이스 갱신 시점 이후의 변경은 반영되지 않을 수 있다.
6. 실무 사용 사례
- 로그 정리: 일정 기간이 지난 로그나 임시 파일 삭제
find /var/log/myapp -name '*.log' -mtime +30 -delete
- 디스크 용량 점검: 큰 파일 찾기
find / -xdev -type f -size +500M 2>/dev/null (-xdev는 다른 파일시스템으로 넘어가지 않음)
- 권한 점검: 모두에게 쓰기가 열린 파일 찾기
find . -type f -perm -o+w
- 빌드·배포 스크립트: 특정 확장자 파일에 일괄 처리
find src -name '*.ts' -exec wc -l {} +
- CI 정리 작업: 캐시 디렉터리나 빈 디렉터리 제거
find . -type d -empty
7. 주의할 점
- `-delete`는 되돌릴 수 없다. 같은 조건으로
-print를 먼저 실행해 대상을 확인한다. 또한-delete는 표현식 맨 끝에 두어야 한다.find . -delete -name '*.log'처럼 앞에 두면 모든 항목이 삭제 대상이 된다. - 글롭 따옴표:
-name *.log처럼 따옴표 없이 쓰면 셸이 현재 디렉터리에서 먼저 확장해 버려 오류나 오동작이 생긴다. 항상'*.log'로 감싼다. - 공백·개행이 있는 파일명:
find ... | xargs는 깨질 수 있다.-print0과xargs -0을 쓰거나-exec ... +를 사용한다. - OR 연산자와 액션:
-o는-a보다 우선순위가 낮다. 괄호로 그룹화하지 않으면 의도와 다른 결과가 나온다. - GNU와 BSD 차이: macOS의 find는 BSD 계열이라 시작 경로 생략이 불가능하고(
find .필요),-printf,-regextype등 일부 GNU 옵션이 없다.touch -d형식도 다르다. - 권한 오류: 접근 권한이 없는 디렉터리는 오류 메시지를 출력한다. 필요하면
2>/dev/null로 stderr를 숨기되, 실제 오류를 놓치지 않도록 주의한다. - 심볼릭 링크: 기본은 링크를 따라가지 않는다. 따라가려면
-L을 사용하지만 순환 참조에 주의한다.
8. 핵심 정리
- find는 시작 경로부터 트리를 재귀 순회하며 조건식을 평가하는 명령어이며, 비용은 방문 항목 수에 비례하는 O(N)이다.
- 표현식은 테스트, 액션, 연산자로 이루어지고 왼쪽에서 오른쪽으로 단락 평가된다. 액션이 없으면
-print가 적용된다. - 글롭 패턴은 따옴표로 감싸고, OR 조건은
\( \)로 묶는다. - 삭제 전에는
-print로 확인하고, 파일명 전달은-print0 | xargs -0또는-exec ... +를 쓴다. - 이식성이 필요하면 GNU find와 BSD find의 옵션 차이를 확인한다.