작은숲:위키노트/Find

큰숲백과, 나무를 보지 말고 큰 숲을 보라.

리눅스에서 find 명령어는 주어진 이름이나 조건에 맞는 파일을 찾고 지정한 명령을 실행한다. find의 기본 구문은 아래와 같다.

find [path...] [expression]

path는 현재 작업 디렉토리(.) 혹은 특정 디렉토리를 지정할 수 있다. 하나 이상의 디렉토리를 지정하는 것도 가능하다. expression에는 옵션과 검색 조건, 실행 명령을 지정할 수 있다. find는 이 글에 나온 옵션과 검색 조건, 실행 명령 외에도 더 많은 것들을 지원하니 자세한 내용은 맨페이지를 참고하도록 하자. 이 글은 find 맨페이지에 나온 내용 중 일부분을 옮긴 것이다.

옵션

-help
--help
사용법을 출력한다.
-version
--version
버전을 출력한다.
-depth
-d
디렉토리에 대해 명령을 실행하기 전에 디렉토리 내에 있는 파일들에 대해 먼저 명령을 실행한다. -delete 명령을 줄 때는 자동으로 이 옵션이 주어진다.
-maxdepth levels
검색과 명령을 실행할 최대 디렉토리 깊이를 지정한다. levels은 양의 정수만 가능하다. 지정한 디렉토리만을 대상으로 할 때 levels1이 된다.
-warn
-nowarn
경고 메시지를 출력하거나 출력하지 않는다.

검색 조건

찾을 대상의 이름 지정

-name name
찾을 대상의 이름을 지정한다. 이때 찾을 이름은 대소문자를 구분한다. '*', '?', '[]' 등의 메타문자를 쓸 수 있다.
  • -name sample – 'sample'이라는 이름을 가진 대상
  • -name "sam*" – 'sam'으로 시작하는 이름을 가진 대상
  • -name "*.txt" – '.txt'로 끝나는 이름을 가진 대상 (확장자가 txt인 대상)[1]
  • -name \*.txt – '.txt'로 끝나는 이름을 가진 대상 ('*'은 셸에 의해 해석되는 메타문자이기 때문에 셸에서 해석되지 않도록 역슬래시('\')를 붙인다)
-iname name
대소문자의 구분 없이 찾을 대상의 이름을 지정한다.
-regex pattern
-iregex pattern
대상의 이름을 찾을 때 정규 표현식을 사용한다. 앞에 'i'가 붙으면 대소문자를 구분하지 않는다.

찾을 대상의 형식 지정

-type type
찾을 파일의 형식을 지정한다.
  • -type f – 일반 파일
  • -type d – 디렉토리
  • -type l심볼릭 링크
  • -type b – 블럭(block)
  • -type c – 캐릭터(character)
  • -type p – 파이프(named pipe, FIFO)
  • -type s – 소켓(socket)

찾을 대상의 타임스탬프 지정

먼저 앞에 붙은 접두어에 따라 어떤 시각을 대상으로 할 것인지 결정된다.

  • m – 대상이 마지막으로 수정된(modified) 시각
  • a – 대상이 마지막으로 읽기 혹은 접근된(accessed) 시각
  • c – 대상의 상태가 마지막으로 변경된(changed) 시각

그리고 시간의 단위가 뒤에 따라온다.

  • min – 분
  • time – 일 (24시간)

이후에는 시간이 나온다. 시간은 숫자이어야 하며, 음수와 양수가 올 수 있다. 음수인 경우에는 '이전', 양수인 경우에는 '이후'를 뜻한다.

-mmin 10
지금으로부터 10분 전의 이후에 수정된 대상
-atime 10
지금으로부터 10일 전의 이후에 읽힌 적이 있는 대상
-cmin -20
지금으로부터 10분 전의 이전에 상태가 변경된 대상

비교 대상을 다른 파일로 지정할 수도 있다.

-cnewer file
file이 수정된 시각 이후에 상태가 변경된 대상
-newer file
file이 수정된 시각 이후에 수정된 대상

찾을 대상의 퍼미션 지정

-perm mode로 찾고자 하는 대상의 퍼미션을 지정할 수 있다. mode에는 숫자 형식의 모드(0775)나 문자 형식의 모드(u=xwr)가 올 수 있다. 그리고 mode의 앞에는 '-', '/', '+', 세 가지의 추가 설정이 붙거나 붙지 않을 수 있다.

  • mode – 정확하게 지정한 모드와 일치하는 대상. 예를 들어, -perm g=w라고 했다면 다른 퍼미션 설정 없이 오직 그룹 쓰기 퍼미션(0020)만 있어야 한다.
  • -mode – 지정한 모드와 모두 일치하는 대상. 예를 들어, -perm g=w라고 했다면 다른 퍼미션은 상관 없이 그룹 쓰기 퍼미션(0664, 0666, 0020 등)이 설정된 경우에 일치한다.
  • /mode, +mode – 지정한 모드 중 어느 하나라도 일치하는 대상. 두 설정은 비슷한 동작을 한다. 하지만 '+'는 추후 삭제될 옵션이므로 '/'을 쓰도록 한다.

찾을 대상의 소유 사용자나 그룹 지정

-gid n
n GID를 갖는 대상
-group gname
gname 그룹의 소유인 대상
-nogroup
설정된 GID가 존재하지 않은 경우
-nouser
설정된 UID가 존재하지 않은 경우
-uid n
n UID를 갖는 대상
-user uname
uname 사용자의 소유인 대상

찾을 대상의 크기 지정

-size n[cwbkMG]
찾을 대상의 크기를 지정한다. 숫자 뒤에 오는 접미사는 단위를 뜻한다.
  • 'b' – 512 바이트 블럭(512-byte blocks, 접미사가 붙지 않았을 때 사용되는 기본 단위)
  • 'c' – 바이트(bytes)
  • 'w' – 워드(2-byte words)
  • 'k' – 킬로바이트(Kilobytes, units of 1024 bytes)
  • 'M' – 메가바이트(Megabytes, units of 1048576 bytes)
  • 'G' – 기가바이트(Gigabytes, units of 1073741824 bytes)

기타 검색 조건

-readable
읽을 수 있는 대상
-writable
쓸 수 있는 대상
-executable
실행할 수 있는 대상
-empty
비어있는 대상
-fstype type
type 파일시스템에 있는 대상으로 제한 (type에는 nfs, ufs, tmp, mfs 등이 올 수 있다)

연산자

find에서 하나 이상의 조건들을 연산자를 통해 연산할 수 있다. 이것은 보통의 프로그래밍 언어에서 사용하는 연산자와 비슷하다.

( expr )
조건식을 괄호로 묶는다. 수학에서와 마찬가지로 괄호로 묶인 연산식이 먼저 연산된다.
! expr
-not expr
부정 연산자. expr 조건식이 참이면 결과값은 거짓이다. ! 연산자의 경우 셸에서 다른 의미로 해석되는 메타문자이기 때문에 \!와 같이 역슬래시를 붙여 셸에서 해석되지 않도록 해야 한다.
expr1 expr2
expr1 -a expr2
expr1 -and expr2
논리곱(AND) 연산자. expr1expr2가 모두 참이어야 참이다. expr1이 거짓이면 expr2는 검사하지 않는다.
expr1 -o expr2
expr1 -or expr2
논리합(OR) 연산자. expr1expr2, 둘 중 하나만 참이면 참이다.
expr1 , expr2
순차(쉼표) 연산자. 조건식에서는 expr1은 연산은 하지만 값은 무시되고, 연산식의 결과값은 expr2가 된다. expr1expr2 둘 모두 실행할 때 유용하다.

실행 명령

-print
검색한 대상의 완전한 경로를 한 줄에 하나씩 화면에 출력한다. 즉 대상의 경로 뒤에 개행문자('\n')를 붙여서 출력한다.
-print0
검색한 대상의 완전한 경로를 화면에 출력한다. 대상의 경로 뒤에는 개행문자('\n') 대신 널문자('\0') 붙여서 출력한다.
-printf format
검색한 대상의 완전한 경로를 format 형식에 맞게 화면에 출력한다. formatC 언어 등에서 사용하는 형식 지정자와 같다.
-fprint file
검색한 대상을 화면에 출력하는 대신 file에 저장한다. file은 없는 경우 새로 만들고, 있는 경우에는 덮어 쓴다. -fprint /dev/stdout-print와 같은 명령이다.
-fprint0 file
검색한 대상의 완전한 경로를 file에 저장한다. 대상의 경로 뒤에는 개행문자('\n') 대신 널문자('\0') 붙인다.
-fprintf file format
검색한 대상을 format 형식에 맞게 file에 저장한다. formatC 언어 등에서 사용하는 형식 지정자와 같다.
-ls
검색한 대상을 ls -dils 명령의 출력 형식처럼 출력한다.
-fls file
검색한 대상을 ls 명령의 출력 형식으로 file에 저장한다.
-delete
검색한 대상을 삭제한다. -depth 옵션을 주지 않아도 자동으로 -depth 옵션에 따라 동작한다.
-exec command ;
-exec command {} ;
검색한 대상에 대해 command 명령을 실행한다. command의 끝은 세미콜론(;)으로 구분 짓는다. 명령창에서 실행할 때는 셸에서는 세미콜론(;)이 특별한 의미를 갖기 때문에 앞에 역슬래시(\)를 붙여서 사용한다. '{}'을 쓰면 command가 인자가 필요한 경우 찾은 대상을 인자로 넘겨준다. -exec rm -rf {} \;.
-exec command {} +
-exec command {} ; 명령은 대상을 하나씩 command의 인자로 넘겨 실행하지만, -exec command {} + 명령은 대상들을 모두 합쳐 마지막에 command의 인자로 넘긴다. 즉 command의 인자는 개별 대상이 아니라 모든 대상의 목록이 된다.
-execdic command ;
-execdir command {} ;
-exec과는 달리 -execdic에서는 하위 디렉토리에 있는 대상부터 명령을 실행한다.
-execdir command {} +
-exec command {} +과 마찬가지로 하위 디렉토리에 있는 대상부터 인자로 넘겨줄 대상의 목록에 포함시켜 마지막에 모든 대상의 목록을 command의 인자로 넘겨준다.
-ok command ;
-exec와 비슷하지만 command를 실행하기 전에 사용자에게 물어본다.
-okdir command ;
-execdir과 비슷하지만 command를 실행하기 전에 사용자에게 물어본다.

예제

find /tmp -name core -type f -print | xargs /bin/rm -f
/tmp 디렉토리 아래에서 'core'라는 이름을 가진 파일을 찾아 삭제한다. -print 명령으로 출력한 값들이 xargs 명령어로 넘어가서 /bin/rm의 인자가 된다. 이 경우 만약 파일 이름에 개행문자나 따옴표, 공백문자가 있으면 오류가 생긴다.
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
/tmp 디렉토리 아래에서 'core'라는 이름을 가진 파일을 찾아 삭제한다. 여기서는 -print0 명령으로 출력한 값들은 널문자로 구분되어 있다. 이것을 xargs 명령어에서 -0 옵션으로 받아 이를 구분해서 /bin/rm의 인자로 넘겨준다. 이 경우에는 파일 이름에 개행문자나 공백문자, 따옴표가 들어가도 오류가 생기지 않는다.
find . -type f -exec file '{}' \;
현재 작업 디렉토리 아래에 있는 모든 파일들을 찾아 그 파일들을 대상으로 file 명령을 실행한다. '{}'\;는 셸에서 원치 않게 해석되는 것을 방지하기 위해 따옴표와 역슬래시를 붙여준 것이다.
find / \( -perm -4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \( -size +100M -fprintf /root/big.txt '%-10s %p\n' \)
여기에서는 두 find 명령을 한번에 실행하게 하고 있다. 이 명령을 실행하면 find는 루트 디렉토리에서부터 setuid가 설정된 파일을 찾아 /root/suid.txt에 저장하고, 크기가 100Mbytes 이상인 파일을 찾아 /root/big.txt 파일에 저장한다. 이 명령에서는 두 가지 find 명령을 실행하지만 전체 파일시스템은 한 번만 탐색하게 된다.
find $HOME -mtime 0
홈 디렉토리 아래에서 지난 24시간 이내에 수정된 파일과 디렉토리 등을 출력한다. -mtime은 조건에 맞는 파일을 찾기 위해 현재 시각에서 파일이 수정된 시각을 뺀 후 24시간으로 나눈다. 그런 후 소수점 이하는 버리기 때문에 24시간이 지나지 않은 값들은 모두 0이 된다. 따라서 -mtime의 인자로 0을 주면 지난 24시간 이내에 수정된 파일을 찾게 된다.
find /sbin /usr/sbin -executable \! -readable -print
/sbin/usr/sbin 디렉토리에서 실행 가능하지만 읽을 수 없는 파일을 찾아 출력한다. 부정 연산자 !는 셸에서 해석되는 메타문자이므로 역슬래시를 붙였다.
find . -perm 664
현재 작업 디렉토리 아래에서 퍼미션이 정확히 644인 파일만 찾는다.
find . -perm -664
현재 작업 디렉토리 아래에서 퍼미션이 664를 포함하는, 즉 소유 사용자와 그룹은 읽기(퍼미션 4)와 쓰기(퍼미션 2)를 할 수 있고 그 외의 사용자는 읽기를 할 수 있는 퍼미션을 갖는 파일을 찾는다. 이 경우 퍼미션이 664, 666, 764, 775, 777 등인 파일이 포함된다.
find . -perm /222
현재 작업 디렉토리 아래에서 퍼미션이 소유 사용자가 쓸 수 있거나, 소유 그룹이 쓸 수 있거나, 다른 사용자가 쓸 수 있는 파일을 찾는다. 즉 사용자나 그룹, 다른 사용자가 누구든 쓸 수 있는 파일이 포함된다. 200, 020, 002, 600, 640, 644, 700, 755 등의 퍼미션을 갖고 있는 파일이 해당된다.
find . -perm /220
find . -perm /u+w,g+w
find . -perm /u=w,g=w
위 세 명령은 같다. 현재 작업 디렉토리 아래에서 소유 사용자가 쓸 수 있거나 소유 그룹이 쓸 수 있는 파일을 찾는다.
find . -perm -220
find . -perm -g+w,u+w
위 두 명령은 같다. 현재 작업 디렉토리 아래에서 소유 사용자와 소유 그룹이 모두 쓸 수 있는 파일을 찾는다.
find . -perm -444 -perm /222 ! -perm /111
find . -perm -a+r -perm /a+w ! -perm /a+x
위 두 명령은 같다. 현재 작업 디렉토리 아래에서 모든 사용자가 읽을 수 있고(-perm -444), 어떤 사용자가 쓸 수 있고(-perm /222), 어떤 사용자도 실행할 수 없는(! -perm /111) 파일을 찾는다.
find /home -empty -print
/home 디렉토리 아래에서 비어있는 파일을 찾아 출력한다.
find . -name "*.php" -ls
현재 작업 디렉토리 아래에서 '.php'로 끝나는 파일(확장자가 php인 파일)을 찾아 ls 명령어의 출력 형식으로 출력한다.
find / -name "test*" -type d -print
루트 디렉토리 아래에서 'test'로 시작하는 디렉토리만 찾아 출력한다.
find /home /var/www /var/log -empty -print
/home, /var/www, /var/www 디렉토리 아래에서 비어있는 파일을 찾아 출력한다.
find . -mtime -10 -exec rm -rf {} \;
현재 작업 디렉토리 아래에서 10일 이전에 수정한 파일(디렉토리 포함)을 찾아 모두 삭제한다.
find . -name "*.php" -exec grep "curl" {} \; -print
현재 작업 디렉토리 아래에서 '.php'로 끝나는 파일(확장자가 php인 파일)을 찾아 내용에 'curl'이 있으면 출력한다.
find . -name "*.php" -exec perl -pi -e "s/hello/hi/g" {} \; -print
현재 작업 디렉토리 아래에서 '.php'로 끝나는 파일(확장자가 php인 파일)을 찾아 내용에 'hello'가 있으면 모두 'hi'로 수정하고 출력한다.
find /var/www/sample -name "*.php" -exec grep -n "function connect_server" {} \;
find /var/www/sample -name "*.php" | xargs grep -n "function connect_server"
/var/www/sample 디렉토리 아래에서 '.php'로 끝나는 파일(확장자가 php인 파일) 중에서 'function connect_server' 문자열(connect_server() 함수 정의)이 있는 파일을 찾아 그 문자열의 줄 번호와 함께 출력한다.
find /home -perm 700 -type d -exec chmod 750 {} \;
chmod 750 `find /home -perm 700 -type d`
/home 디렉토리 아래에서 퍼미션700인 디렉토리를 찾아 750으로 수정한다.
find /home -maxdepth 2 -name ".bash_history" -exec grep -H "rm" {} \;
사용자 중에 최근 rm 명령어를 사용한 적이 있는지 확인한다.
tar zcvf last-mod.tar.gz $( find . -type f -mmin -60 )
현재 작업 디렉토리 아래에서 1시간 이전에 수정된 파일들만 찾아 last-mod.tar.gz 파일로 압축한다.

참고

주석

  1. 엄밀하게 이야기해서 리눅스에는 '확장자'라는 개념은 없다. 하지만 대부분의 경우 파일이 어떤 형식을 가진 파일인지 쉽게 알 수 있도록 윈도우의 확장자처럼 그 파일의 형식을 나타내는 문자열을 추가한다.
이 작은숲 문서의 출처는 위키노트의 위키노트/Find 문서입니다.