Computer/LINUX

find

알찬돌삐 2012. 8. 10. 16:09

  find 를 제법 잘 쓰는 사람은 다 아는 얘기일 것 같지만, 흔히들 사용하면서도 그 많은 옵션이 잘 안들어오는 사람들을 위해 정리하고자 글을 써본다.

find의 철학은 그 이름에서 이미 감춰져 있다고 해도 과언이 아니다.
find를 통해서 할 수 있는 것이 고작 원하는 이름의 혹은 원하는 속성을 가진 파일을 찾는 것이라 생각한다면 그것은 정말 누구나 사용할 줄 아는 방법으로서의 find 이다.

find의 철학은 다음과 같다. 어디에 이런 글이 쓰여있는지는 나도 모르겠지만, 경험상 정리하자면,

find 는 true/false에 의한 directory 탐색기이다.

신선한가? 그렇다면 계속 읽을 정도로 find라는 처녀 혹은 꽃미남에 대해 호기심을 가질 만한 사람이라 생각하시라.



우선 다들 그러하듯이 man find를 한번 수행해보고 true/false라는 말이 얼마나 나오는지 한 번 살펴보시라. 가능하면, 리눅스의 man find와 솔라리스의 man find를 비교하는 것도 좋을 것이다.

살펴보니 리눅스보다 솔라리스에서 더 많은 true/false라는 말을 발견하게 될터인데, 솔라리스 쪽은 의도 중심적인 표현이고 리눅스쪽은 사용자 중심쪽 표현이기 때문일 것이다.

예 1) find /usr/include -name '*.h'

위 문장은 확장자가 .h 인 파일들을 /usr/include에서 찾는 다는 것을 쉽게 알 수 있다. 하지만, man page를 자세히 읽어보면, 이 문장은 다음과 같이 해석될 수 있다.

만약 현재 스캔하고 있는 파일의 이름이 '*.h'에 일치한다면 참이며, 참인 조건으로 더이상의 비교를 하라는 지시가 없으므로 함축된 -print를 수행한다. 즉,
find /usr/include -name '*.h' -print
라고 명시적으로 밝히는 것과 동일하다.

예 2) find /usr/include -name '*.h' -ls

HPUX find에는 -ls 명령이 없지만 솔라리스와 리눅스에는 존재하므로 설명을 드리자면, 위의 문장은 '*.h'에 일치하는 파일에 대하여 ls -l 과 같은 명령을 수행했을 때 처럼 자세한 정보를 출력하게 된다.
-ls를 설명하고자하는 것이 아니라, 이 문장을 true/false 이론(?)에 근거하여 다시 설명하자면,

이름이 '*.h'에 일치하게 되면 ls -l 을 수행한 결과를 화면에 나타내라라는 뜻이다.

즉,

find /usr/include -name '*.h' -a -ls

라는 뜻이다. find 의 여러 연산자 중에 -a, -o 는 각각 AND, OR를 의미한다. man page에는

-and is assumed where the operator is omitted. (linux)

Expression [ -a ] Expression - Concatenation of expressions (the AND operation is implied by the juxtaposition of two primaries or may be explicitly stated as -a) (aix; solaris, hpux도 같다)


라는 것을 알 수 있다. (리눅스에만 존재하는 -and는 -a와 같은 뜻이다.)

즉, 쉽게 사용해 왔던,

find -name '*.h' -exec grep 'size_t' {} \;

이런 류의 것들이 실은

find -name '*.h' -a -exec grep 'size_t' {} \;

와 같이 해석된다는 것이다.



지금까지 눈에 씌여 있던 귀차니즘의 막을 걷는 작업을 하였다.
-print 와 -a 는 실상 find의 철학을 잊고 쉽게 사용할 수 있는 유틸리티로 만드는 일종의 음모였다라고 생각하시라.

자, 다음과 같은 것은 어떻게 표현해야할까? /usr/include 에 수행한다고 가정하고,

  • .h가 들어가지 않은 것들에 대한 리스트
  • grep size_t 로 한 줄도 출력되지 않는 헤더파일들
  • 헤더하나를 a.h 로 복사해 왔는데, 이것과 일치하는 파일


첫번째 것은 두 가지 방법으로 가능하다.
find /usr/include ! -name '*.h'
find /usr/include -name '*.h' -o -print
처음 방법이야 흔히 사용하던 표현식의 반대이므로 바로 이해될 것이고, 두번째는 -o 즉, OR라는 것은 처음것이 거짓인 경우 두번째 것을 해봐야 참값을 알 수 있는 수식으로 C언어나 스크립트 언어들을 익혀 봤다면 흔히 쓰이는 트릭(?)으로 잘 알 수 있을 것이다.

두 번째는 일단, grep 의 exit status가 한 줄이라도 발견하면 정상 값을 돌리고 그렇지 않으면 오류값을 돌린다는 사실을 알아야한다.

$ grep -q size_t /usr/include/stdio.h
$ echo $?

size_t 대신 다른 것으로 확인해보면, 발견되면 정상(0), 없는 것이면 오류(1)를 나타냄을 알 수 있다. solaris의 경우 grep 을 /usr/xpg4/bin/grep 을 사용하도록 PATH를 조절하는 것이 -q를 사용할 수 있다. -q는 quiet의 의미를 가진다. 즉, 우리는 exit status만 관심있다는 의미이다.

그러면 두 번째 질문도 다음과 같이 표현 할 수 있다.

find /usr/include -exec grep -q size_t {} \; -o -print

즉, {}에 치환하여 grep 을 수행해본 결과 참이아니라면, 즉 한 줄도 발견되지 않았다면(-o) 출력하라(-print).

세 번째 질문은 cmp를 사용하면 된다. 여기에도 귀엽게스리 -s 옵션이 있다. (많은 유틸리티든지 이런 용도로 사용되는 옵션이 있다. s는 silent !)

find /usr/include -exec cmp -s a.h {} \; -a -print



이 페이지는 find 옵션들을 설명하려는 것이 아니라 철학을 설명하는 것이므로, 더 가렵더래도 긁어주지 않음을 용서하시라.

find 는 뒤에 붙은 장황한 옵션, 명령들에 대해서 참 거짓을 확실히 정할 때까지 계속 수행하는 것을 염두에 둔다면 -a, -o, 그리고 \(, \)로 사용할 수 있는 여러 조합에 대해 상상의 날개를 펼칠 수 있을 것이다.

다시 말하지만, find 는 true/false를 기반으로하는 디렉토리 탐색기이다.



Tip
많이 쓰일만한 표현으로 CVS와 .deps를 제외하여 search하려면,

find . -name CVS -a -prune -o -name .deps -a -prune -o -print

이렇게 쓸 텐데,

이 의미는, CVS 를 만나면 -prune 을 수행해봐야 알 수 있고 (-a 이므로),
-prune 은 man page에서 true를 되돌린다고 되어 있으므로,
여기까지의 계산식은 참이되며, 다음이 -o 이므로 더이상 계산할 필요가 없이 끝내게 된다.

-a 는 언제든지 생략가능하므로,

find . -name CVS -prune -o -name .deps -prune -o -print
find . \( -name CVS -o -name .deps \) -prune -o -print

로 사용가능하다.

 

 

 

가장 쉬운 방법은 touch라는 명령어와 find를 사용하시면 됩니다.

 

#touch -t 200505030000 a.txt     --> 2005년 5월 3일 0시 날짜를 갖는 파일 생성

#touch -t 200505070000 b.txt    --> 2005년 5월 7일 0시 날짜를 갖는 파일 생성

#find / -newer a.txt -a ! -newer b.txt -ls  >aaa.txt --> a.txt 생성날짜 이후부터 b.txt 생성날짜 이전을 검색하여 aaa.txt에 저장

 

 

 

며칠전부터 며칠전까지 이런 경우는 다음도 괜찮습니다.


그리고  -type 옵션으로 결과에 디렉토리는 포함되지 않게 하시는 것이 더 맞지 않을까

합니다.

 

find로 찾은 결과가  /tmp/log(디렉토리) /tmp/aaa(파일)

-exec으로 ls를 실행하면 ls -l /tmp/log;ls -l /tmp/aaa 이런 식으로 실행되어

찾은 결과가 디렉토리인 경우 절대경로없이 그 아래의 모든 파일이 다 나오게 됩니다.

따라서  find의 -ls 옵션을 쓰시거나 ls의 -d옵션을 쓰시면 이런 경우를 방지할 수 있습니다.

 

말씀하신 것은 다음 정도가 가능하겠네요.

예를 들어 /tmp/data에서 2일전부터 4일전까지 수정한 파일을 찾는 경우라면

 

find /tmp/data -mtime -4 -mtime +2 -type f -ls

find /tmp/data -mtime -4 -mtime +2 -type f -exec ls -l {} \;

디렉토리까지 같이 찾는 경우라면

find /tmp/data -mtime -4 -mtime +2 -ls

find /tmp/data -mtime -4 -mtime +2 -exec ls -ld {} \;

처럼 하셔도 되겠습니다.

찾는 날짜가 계산이 어렵거나 시간대까지 지정해야 한다면 먼저 답하신 분처럼

mtime 대신 -newer 옵션을 사용하시는 것이 맞습니다.

 

 

이 글은 스프링노트에서 작성되었습니다.

.

'Computer > LINUX' 카테고리의 다른 글

pam_abl 을 통한 SSH 공격방어  (0) 2012.08.10
PAM (착탈형 인증 모듈)  (0) 2012.08.10
mysql ssh 터널링  (0) 2012.08.10
iostat  (0) 2012.08.10
freeSSHd 와 cwRsync 를 이용한 윈도우간의 파일 동기화 따라하기  (0) 2012.08.10