유닉스에서 find 기능 이용하기

유닉스에서 find 기능 이용하기

등록: 한빛미디어(주) (2002-04-02 16:53:17)
저자: 드루 라빈, 역 이호재

find 명령어는 유닉스 시스템에서 가장 강력한 유틸리티중의 하나임에 틀림없습니다.

이번 기사에서 find 명령의 문법에 대해 알아보고, 실질적인 예제를 살펴보도록 하겠습니다.

명령어 자체는 매우 간단한 문법을 지니고 있습니다.

find where_to_search expressions

expression 부분은 처음 find를 사용할 때 상당히 혼란스러운 부분입니다. 또한 이 부분은 유닉스마다 조금씩 다른 문법을 가지고 있습니다. 그래서 새로운 시스템에서 find를 이용하고자 한다면 find의 맨페이지를 살펴봐야 합니다. FreeBSD에서 많이 사용되는 expression은 다음과 같습니다.
-name 와일드카드와 함께 사용될 때에는 반드시 따옴표로 묶어야 함
-type 예를 들면 f=file d=directory l=link
-user 이름이나 UID
-group 이름이나 GID
-perm 권한을 지정
-size 다음 512바이트 블럭까지 찾음. byte로 지정하기 위해서는 c를 사용
-atime 파일이 읽힌 가장 최근 시간
-ctime 파일의 소유자나 권한이 바뀐 가장 최근 시간
-mtime 파일이 수정된 가장 최근 시간
-newer 주어진 파일보다 나중에 만들어진 파일을 찾음
-delete 찾은 파일을 삭제
-ls ls -dgils 와 같은 결과를 출력
-print find 명령의 실행 결과를 출력
-exec command {} \; command를 실행. 문법에 주의
-ok 명령어가 실행되기 전 exec대신 사용
-depth 주어진 디렉토리의 루트 디렉토리가 아닌 그 디렉토리의 가장 낮은 레벨에서부터 시작
-prune 어떤 서브 디렉토리를 제외하고자 할 때 사용

위 와 같은 표현식을 어떻게 사용하고 결합하는가에 대한 예제를 곧 알아보도록 하겠습니다. 이를 알아 보기 전에 find가 어떤 목적에 쓰여지는가에 대해 알아볼 필요가 있습니다. find가 무엇인지를 알기 위해 whatis 명령어를 사용해 본다면, 답변은 놀랍게도 다음과 같을 것입니다.

whatis find
find(1) - walk a file hierarchy

대 략적으로 보자면, find는 당신이 선택한 어떤 표현식에 맞는 파일들을 찾기 위해 디렉토리를 재귀적으로 검색하는 것을 의미합니다. 이러한 기능이 별것 아닌 것처럼 보일수 있지만, 디렉토리와 그 모든 서브 디렉토리를 검색할 수 있는 유닉스 유틸리티는 많지 않습니다. 이러한 유용한 기능은 파일을 찾는 것뿐만이 아니라 다른 일도 할 수 있습니다.

이제 간단한 예제를 살펴보고 좀 더 어려운 표현식에 대해서 살펴보도록 하겠습니다. 가장 간단한 find 사용법은 다음처럼 간단합니다.

find . -print

"."는 당신의 현재 디렉토리를 의미하기 때문에, 이 find 명령어는 현재 이 명령어가 실행되고 있는 디렉토리와 그 모든 서브 디렉토리에 있는 파일을 찾아서 화면에 출력할 것입니다.

FreeBSD 시스템에서 -print는 default 옵션입니다. 그렇기 때문에 아래의 명령어는 위와 똑같은 결과를 보여줍니다.

find .

하지만 -print 옵션을 default로 하지 않는 시스템도 있기 때문에 -print 옵션을 쓰는 습관을 들이는게 좋습니다.

만약 당신이 home 디렉토리에 있는 모든 파일을 찾고자 한다면, 먼저 지금 현재 home 디렉토리에 있는지 확인한 후 find 명령을 내려야 합니다. (아래 참조)

cd
find . -print

cd 명령어는 당신을 home 디렉토리로 이동시켜 줍니다. find 명령어를 통해서 매우 강력한 일을 할 수 있기 때문에, find 명령을 실행시킬 디렉토리로 우선 이동한 후 작업을 시작하는 것이 좋은 습관입니다. 지금부터 필자는 당신이 home 디렉토리에 있다고 가정할 것이고, 이는 부주의로 인해 home 디렉토리 이외의 다른 파일에 나쁜 영향을 끼치는 것을 방지할 것입니다.

위 에서 살펴본 예제는 find 명령어가 얼마나 사용하기 쉬운지를 보여주기 위해 쓰여졌습니다. 하지만, 보통 find 명령을 내릴 때에는 특정한 조건에 맞는 것을 찾길 원할 것입니다. 이제 다른 표현식이 나올때가 된 것입니다. 특정한 이름을 갖는 파일을 찾아보도록 합시다.

touch file1
find . -name file1 -print
./file1

위 의 명령어를 하나하나 살펴보도록 하겠습니다. 먼저 touch 명령어를 이용해서 이름이 file1인 빈 파일을 하나 생성하였습니다. 그리고나서 find 명령을 내릴때 현재 디렉토리(".")에서부터 찾을 것이며 파일이름(-name)이 file1인 것을 찾고 그결과를 화면에 출력하라는 옵션을 주었습니다. 위의 결과에서 file1이 하나 출력되었기 때문에 필자는 현재 디렉토리와 그 하위 디렉토리에 파일이름이 file1인 것은 단 하나 존재한다고 말할 수 있습니다.

보통 find 명령어를 사용해 파일을 찾을 때 찾는 파일이 하나 이상일 것입니다. 예를 들면 특정한 확장자를 갖는 모든 파일을 찾는 것입니다. 필자는 .pdf 파일들을 많이 다운로드하는 경향이 있는데, 그 파일들이 어디에 존재하는지는 잘 기억하지 못합니다. 이제 그것들을 모아서 기존에 존재하는 pdfs라는 디렉토리에 넣고자 합니다. 필자의 home 디렉토리와 그 하위 디렉토리에서 확장자가 .pdf인 모든 파일을 찾고자 한다면 다음과 같이 명령을 내리면 됩니다.

find . -name "*.pdf" -print
./pdfs/50130201a.pdf
./pdfs/50130201b.pdf
./pdfs/50130201c.pdf
./pdfs/IWARLab.pdf
./pdfs/DoS_trends.pdf
./pdfs/Firewall-Guide.pdf
./2000_ports.pdf

최근에는 필자가 비교적 정리를 잘 한 것 같습니다. pdfs이외의 디렉토리에 있는 pdf파일이 하나밖에 없으니까요.

한 가지 주목해야 할 점은 위의 명령어를 사용할때 *.pdf를 항상 인용부호로 감싸줘야 한다는 것입니다. 즉 *.pdf 대신 "*.pdf"를 사용해야 합니다. 인용부호로 감싸는 방법이 두가지 더 있습니다. 다음의 두 명령어는 똑같은 결과를 출력합니다.

find . -name \*.pdf -print
find . -name '*.pdf' -print

이 의 명령어에 명령어를 추가해보고 결과가 어떻게 바뀌는지 살펴보도록 합시다. 만약 pdfs 디렉토리 내에 있지 않은 pdf 파일만을 찾고자 한다면 어떻게 해야 할까요? 위의 명령어의 결과를 pipe를 통해 grep에게 전달하면 됩니다.

find . -name "*.pdf" -print | grep -v "^\./pdfs/"
./2000_ports.pdf

음... 위의 명령어는 동작을 합니다만 문법이 꽤 이상해 보입니다. 이를 분석해 보도록 하겠습니다. grep에서 -v는 역필터를 설정하는 옵션입니다. 즉 grep -v 다음에 나오는 것과 반대되는 것을 보여주는 것입니다. 이번 예에서 ./pdfs/에 들어있는 파일들은 필요 없기 때문에 ./pdfs/에 들어 있지 "않은" 파일을 찾아야 했고 그래서 -v 옵션을 사용했습니다. 또 전체 표현식을 인용부호로 감싼 것을 볼 수 있습니다. 그리고 추가적인 문자인 ^\ 를 볼 수 있습니다. ^는 grep에게 표현식이 각 라인의 1열에서부터 일치한 것만을 찾으라고 말하는 것입니다. \는 .를 특별한 문자로 해석하지 못하게 하기 위해 쓰인 추가적인 인용부호입니다. 표현식 전체는 grep에게 ./pdfs/ 디렉토리에 있지 않는 파일들을 보여달라는 것을 의미합니다. 그래서 원하는 결과를 얻었습니다.

용감하게도 좀더 유용하고 복잡한 것을 찾고 있습니까? find는 파일을 찾는 일 뿐만이 아니라 파일을 올바른 디렉토리로 옮기는 일도 할 수 있습니다. 다음의 예제를 살펴보도록 하겠습니다.

find . -name "*.pdf" -print | grep -v "^\./pdfs/" | xargs -J X mv X ./pdfs/

이 명령어가 정확하게 작동했는 지를 알아보기 위해 원래의 find 명령어를 반복하겠습니다.

find . -name "*.pdf" -print
./pdfs/50130201a.pdf
./pdfs/50130201b.pdf
./pdfs/50130201c.pdf
./pdfs/IWARLab.pdf
./pdfs/DoS_trends.pdf
./pdfs/Firewall-Guide.pdf
./pdfs/2000_ports.pdf

위 에서 볼 수 있듯이 정확하게 동작하였습니다. 왜 그런지 살펴보도록 하겠습니다. 일단 grep은 find 의 결과를 필터링 하였습니다. 그 grep의 결과값이 pipe를 통해 xargs 명령어로 전달이 되었고 우리가 원하는 일이 완료되었습니다. J 스위치는 xargs 명령어에게 stdin으로 들어오는 모든 파일들을 소스로, 명령어 다음에 나오는 파일을 목적지로 가정하게 합니다. 예를 들면 필자가 find 명령을 내리기 전에는 얼마나 많은 파일들을 옮겨야 하는지 알 수 없었습니다. 하나일수도 있고 여러개일수도 있기 때문입니다. 필자는 찾은 파일이 몇개인지 상관없이 xargs가 해당 파일 모두를 pdfs 디렉토리로 옮기게 하고 싶었습니다. 이러한 일종의 마법같은 작업이 J 스위치로 인해 가능합니다. 또한 J 스위치가 올바르게 작동하기 위해서 X라는 문자열을 정의하였고 mv 다음에 삽입하였습니다.



한권으로 끝내는 유닉스

유 닉스 파일은 확장자가 없을 수 있다는 것을 기억해야 합니다. 그래서 좀 더 복잡한 패턴에 일치하는 파일을 찾을 수 있어야 합니다. 예를 들면 파일 이름안에 "bsd"가 들어 있는 것을 찾고 싶다면 다음과 같은 명령어를 내리면 됩니다.

find . -name "*bsd*" -print
./.kde/share/icons/favicons/www.freebsd.org.png
./.kde/share/icons/favicons/www.freebsddiary.org.png
./.kde/share/wallpapers/bsdbg1280x1024.jpg
./mnwclient-1.11/contrib/freebsd

우리는 물론 파일이름뿐만 아니라 다른 것으로도 파일을 찾을 수 있습니다. 예를 들면, 여러분이 읽은지 30일 이상이 지난 파일들을 찾고자 한다면 다음과 같이 하면 됩니다.

find . -atime +30 -print

수정하지 않은 파일을 찾고자 한다면 -mtime을 사용하면 됩니다. 그리고, 소유권을 변경하지 않은 파일을 찾고자 한다면 -ctime을 사용하면 됩니다. + 다음의 숫자는 날짜를 의미합니다. 오늘 변경된 파일을 찾고자 한다면 다음과 같이 하면 될 것입니다.

find . -mtime -1 -print

이는 24시간내에 수정된 파일을 찾아서 보여줍니다. 이번 예제에서는 하루 이전의 파일에 관심이 있기 때문에 - 옵션을 사용한 것에 주목하시기 바랍니다.

시 간에 관한 또다른 스위치는 -newer 입니다. 위에서 알아본 3가지 시간에 관한 스위치는 모두 24시간 단위로만 사용이 가능합니다. 좀 더 작은 시간 단위에서 작업을 하고자 한다면 - newer 스위치를 이용할 수 있습니다. 이를 이용해 1분 단위로 파일의 접근이나 수정, 변경을 비교할 수 있습니다. 예를 들면 여러분이 .cshrc 파일을 수정한 이후에 수정된 .으로 시작하는 파일을 찾고자 한다면, 다음과 같이 하면 됩니다.

find . -type f -name ".*" -newer .cshrc -print

여 기에 -type이란 새로운 스위치가 있습니다. 이는 파일의 타입을 지정하는 스위치인데 디렉토리가 아닌 파일만을 찾기 위해 -type f를 추가했습니다. 그리고 -name 스위치를 통해 이름이 .으로 시작하는 파일을 찾고자 했으며 마지막으로 -newer 스위치를 이용해 .cshrc 파일을 수정한 이후에 수정된 파일들을 찾도록 하였습니다.

여러 스위치를 결합해서 사용할때 -o 나 논리 or를 사용하지 않는다면 모든 결과는 논리적인 and 의 결과입니다. 위에서도 모든 스위치가 논리적 and로 결합되어 있기 때문에 find는 이러한 조건(타입이 파일이고 어떤 특정한 이름을 가지고 있고 .cshrc파일보다 이후에 수정된)을 모두 만족하는 것을 찾아줄 것입니다.

논리적 and 와 논리적 or의 차이를 알아보도록 하겠습니다. 만약 필자의 홈디렉토리에 있는 7일이상 접근하지 않고 크기가 10MB이상인 파일을 찾고자 한다면 다음과 같이 하면 됩니다.

find . -atime +7 -size +20480 -print

하지만 만약 7일 이상 접근하지 않은 파일 이거나 크기가 10MB이상인 파일을 찾고자 한다면 다음처럼 해야 합니다.

find . -atime +7 -o -size +20480 -print

여기서 -size 스위치를 사용하기 위해서 약간의 계산이 필요하다는 것을 알 수 있습니다. 이는 -size가 크기를 512바이트 단위로 인식하기 때문입니다. 하지만 다음과 같이 한다면 계산은 필요없습니다.

find . -atime +7 -o -size +`expr 10 \* 1024 \* 2` -print

위 의 예제에서 backquotes(`) 사이에서 우리가 필요로하는 계산을 한다는 것을 주목해야 합니다. (`는 키보드의 가장 왼쪽 상단에 있습니다.) 우리는 10MB 이상의 파일을 찾길 원하기 때문에 backquotes 앞에 +가 여전히 존재합니다. find 명령어 앞에 echo를 더해서 그 결과가 무엇인지 미리 알아볼 수도 있습니다.

echo find . -atime +7 -o -size +`expr 10 \* 1024 \* 2` -print
find . -atime +7 -size +20480 -print

위와 같이 복잡한 명령어를 실행할 때에는, backquote를 한 것이 올바른 결과를 출력하는지 등을 미리 검사해 보는 것이 좋은 습관입니다.

드루 라빈은 킹스톤에 있는 사립 공과 대학에서 네트웍을 가르치고 있습니다. 그녀는 하나의 테스트 컴퓨터에서 얼마나 많은 운영체제를 멀티 부팅할 수 있는지 알아보는 것으로 유명합니다.

Copyright © 2006 Hanbit Media, Inc.

댓글 없음: