Devin.KR
로그인

리눅스 find 명령어 사용법 - 파일 검색과 -exec, -mtime 실전 예제

개발자 조회 1

이 명령어를 언제 쓰는가

디스크가 찼을 때 큰 파일을 찾고, 30일 지난 백업을 지우고, 어제 누가 뭘 수정했는지 추적하는 일이 전부 find 다. 파일명을 아는 경우에는 locate 나 셸 와일드카드로 충분하지만, "언제 수정됐는가", "몇 MB 이상인가", "소유자가 누구인가" 같은 속성 조건으로 찾아야 하면 find 밖에 없다.

찾은 다음 무언가를 실행하는 것까지가 find 의 진짜 용도다. -execxargs 조합을 익히면 대량 파일 정리 작업이 한 줄로 끝난다. 동시에 실수 한 번에 파일이 대량으로 사라지는 명령이기도 하므로 삭제 전 확인 절차를 반드시 몸에 붙여야 한다.

기본 형식

find [검색 시작 경로] [조건] [동작]

세 부분이 순서대로 온다. 경로를 생략하면 GNU find 는 현재 디렉터리를 쓰지만, BSD/macOS 는 경로가 필수다. 스크립트에는 항상 find . ... 처럼 경로를 명시한다. 동작을 생략하면 -print 가 적용되어 경로를 출력한다.

자주 쓰는 옵션

옵션의미예시
-name파일 이름이 패턴과 일치 (대소문자 구분)find . -name '*.log'
-iname이름 일치, 대소문자 무시find . -iname 'readme*'
-type종류 지정. f 파일, d 디렉터리, l 심볼릭 링크find /var -type d -name 'cache'
-mtime N수정된 지 N일 (+N 초과, -N 이내)find /backup -mtime +30
-mmin N수정된 지 N분. 방금 무엇이 바뀌었는지 볼 때find /etc -mmin -60
-size N크기. +100M, +1G, -10kfind / -type f -size +1G
-maxdepth NN단계까지만 내려간다. 다른 조건보다 앞에 온다find . -maxdepth 2 -name '*.conf'
-user / -group소유자 / 그룹으로 찾는다find /data -user www-data
-perm권한으로 찾는다find /home -perm 0777
-exec ... \;찾은 파일마다 명령을 한 번씩 실행find . -name '*.tmp' -exec rm {} \;
-exec ... +찾은 파일을 모아서 명령 한 번에 넘긴다 (훨씬 빠름)find . -name '*.log' -exec ls -lh {} +
-print0구분자를 널 문자로. 공백 든 파일명 대비find . -print0 | xargs -0 ls -l
-delete찾은 것을 삭제한다. 조건 뒤 맨 끝에 둔다find /tmp -name 'sess_*' -mtime +7 -delete

실전 예제

1) 디스크를 채우고 있는 큰 파일을 찾는다. df 로 용량이 찬 걸 확인한 다음 바로 이어서 치는 명령이다.

find /var -type f -size +500M -exec ls -lh {} + 2>/dev/null

2>/dev/null 은 권한 없는 디렉터리의 Permission denied 메시지를 걷어내려는 것이다.

2) 30일 지난 백업 파일을 정리한다. 삭제 전에 목록부터 확인하는 것이 원칙이다.

find /backup -type f -name '*.sql.gz' -mtime +30          # 먼저 목록 확인
find /backup -type f -name '*.sql.gz' -mtime +30 -delete   # 확인한 뒤 삭제

3) 최근 한 시간 안에 바뀐 설정 파일을 찾는다. "누가 뭘 건드렸길래 갑자기 죽었나"를 추적할 때 쓴다.

find /etc -type f -mmin -60 -ls

4) 특정 확장자 파일 안에서 문자열을 검색한다. grep 만으로 하기 어려운, 대상 파일을 정교하게 고르는 경우다.

find . -type f -name '*.py' -print0 | xargs -0 grep -n 'DEBUG = True'

5) 배포 후 권한과 소유권을 일괄 정정한다. root 로 압축을 푼 뒤 서비스가 파일을 못 읽을 때 쓴다.

find /srv/app -type d -exec chmod 755 {} +
find /srv/app -type f -exec chmod 644 {} +
chown -R www-data:www-data /srv/app

6) 빈 디렉터리를 정리한다. 파일만 지우고 남은 껍데기 디렉터리를 치울 때다.

find /var/spool/upload -type d -empty -delete

함정과 주의점

-delete 는 반드시 조건 뒤 맨 끝에 온다. find 는 인자를 왼쪽부터 순서대로 평가한다. 아래 두 명령의 결과는 하늘과 땅 차이다.

find /tmp -name '*.tmp' -delete    # 정상: .tmp 파일만 지운다
find /tmp -delete -name '*.tmp'    # 사고: /tmp 아래 전부를 지운다

두 번째는 이름 조건을 보기 전에 삭제부터 하기 때문이다. 삭제 명령은 -delete 를 빼고 먼저 돌려서 목록을 눈으로 확인한 뒤에 붙인다. 이 절차 하나가 대형 사고를 막는다.

-mtime +7 은 "7일보다 오래된"이지 "7일 이상"이 아니다. find 는 경과 시간을 24시간 단위로 나눈 뒤 소수점을 버린다. 그래서 -mtime +7 은 실제로 8일을 넘긴 파일부터 걸린다. 정확히 며칠치를 남길지가 중요한 보관 정책이라면 -mtime +6 처럼 한 칸 조정하거나 -mmin 으로 분 단위 계산을 쓴다.

파일명에 공백이 있으면 파이프에서 깨진다. find . -name '*.log' | xargs rmmy report.logmyreport.log 두 개로 나눠 인식한다. 있지도 않은 my 를 지우려 하거나, 최악의 경우 엉뚱한 파일을 지운다. 반드시 -print0xargs -0 을 짝으로 쓰거나, 아예 -exec ... + 를 쓴다.

-name 은 경로가 아니라 파일명만 본다. find . -name 'src/*.js' 는 아무것도 못 찾는다. 경로 전체로 매칭하려면 -path './src/*.js' 를 쓴다.

-maxdepth 를 조건 뒤에 쓰면 경고가 뜬다. GNU find 는 warning: you have specified the global option -maxdepth after the argument -name 같은 경고를 낸다. -maxdepth 는 위치와 상관없는 전역 옵션이라, 뒤에 써도 앞에 놓인 조건까지 포함해 검색 전체에 적용된다. "이 조건부터만 깊이를 제한하겠다"는 의도로 뒤에 두면 그 의도대로는 동작하지 않는다는 뜻이다. 헷갈릴 일이 없게 항상 경로 바로 뒤에 둔다.

-exec ... \; 는 파일마다 프로세스를 새로 띄운다. 파일이 10만 개면 프로세스를 10만 번 만든다. 명령이 여러 인자를 받을 수 있으면 + 로 끝내는 편이 수십 배 빠르다.

함께 보면 좋은 명령어

  • xargs — find 결과를 다른 명령에 넘기는 표준 짝. 병렬 처리(-P)까지 된다.
  • du — 어느 디렉터리가 용량을 먹는지 먼저 좁힌 다음 find 로 파일을 특정한다.
  • locate — 이름만 알면 되는 경우 인덱스를 뒤지므로 비교할 수 없이 빠르다.