find utility 의 철학

pynoos의 이미지

아래는 제 블로그에 있는 글(http://coolengineer.com/68)을 같이 공유하고자 옮겨온 것입니다.
옮기려다보니 문체가 개인 홈페이지에 있을 때와 여기에 있을 때가 확 다르군요.. :( 용서하시면서 읽어주시어요...

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

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

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

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

신선한가?

-----------------------------------------------------------------------------
우선 다들 그러하듯이 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 에 수행한다고 가정하고,
<ul> <li>.h가 들어가지 않은 것들에 대한 리스트 <li>grep size_t 로 한 줄도
출력되지 않는 헤더파일들 <li>헤더하나를 a.h 로 복사해 왔는데, 이것과 일치하는
파일 </ul> 첫번째 것은 두 가지 방법으로 가능하다. 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를 기반으로하는 디렉토리 탐색기이다.

-------------------------------------------------------
끝까지 읽어주셔서 감사합니다.

Forums: 
hey의 이미지

훌륭한 강좌입니다 !!


----------------------------
May the F/OSS be with you..


랜덤여신의 이미지

아하... -and 나 -or 는 패턴 매칭 말고 -exec 에도 적용되는 것이였군요...!
음 많은 부분에 적용이 가능하겠네요. 고맙습니다. :o

pynoos의 이미지

감사합니다.

많이 쓰일만한 표현으로 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

로 사용가능 합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.