Shinnara's Blog
Talking with Shinnara :: NaraTalk.com


요  며칠 C 코드에 있는 특정 문자열에 대한 처리를 가지고 글을 몇개 올리고 있었습니다. Java 로 먼저 짠 프로그램을 Perl 로 변환하는 작업을 하고 있는데요, 하다 보니 Perl 에 대해 좀더 많이 알아가는 것 같습니다.

오늘 올릴 글은 한국 펄 사용자 모임에 올라온 Tip 중의 하나 입니다. Java 로 작성한 프로그램에서 입력값으로 디렉토리도 받을 수 있도록 하고 있었습니다.  입력된 값이 디렉토리인 경우, 하위 디렉토리에 있는 C 파일에 대해서도 처리를 하도록 했습니다. 그렇게 하기 위해 traverse()라는 함수를 만들었었는데요, 이를 Perl로 구현하기 위해 관련 자료를 찾던 중 알게되었습니다.

방법은 간단합니다. File::Find 를 쓰면 무척 쉽더군요.

find( \&traverse, 'target');  # File:Find 의 Search Function
sub traverse {

   my $filename =  $File::Find::name;
   if( (-f $_) && ($filename =~ /\.c$/))
      { # c 파일만 처리         
        replace( $filename);
      }  

} # end of sub traverse

find 의 인자로 subroutine 과 초기 디렉토리를 넘겨줍니다. 그러면 find는 하위 디렉토리를 검색하면서 각 항목에 대해 find 호출 시 받은 subroutine을 호출하게 됩니다. 위의 프로그램에서는 traverse 가 불리게 됩니다.  $File::Find::name 은 파일 이름을, $File::Find::dir은 해당 파일에 대한 디렉토리 명을 알려줍니다. 만약 target이라는 하위 디렉토리에 A.c B.c C.c 라는 파일이 있다면 $File::Find::name 의 값은 각각 target/A.c target/B.c tartget/C.c 가 되고 $File::Find::dir 의 값은 target 이 됩니다.

!! 주의

File::Find
CPAN에 있는 설명을 보면 아래와 같은 문구가 있습니다.

find() does a depth-first search over the given @directories in the order they are given. For each file or directory found, it calls the &wanted subroutine. (See below for details on how to use the &wanted function). Additionally, for each directory found, it will chdir() into that directory and continue the search, invoking the &wanted function on each file or subdirectory in the directory.

find() 에 의해 자동으로 디렉토리가 바뀌는 점에 주의를 기울여야 합니다. 위의 코드에서는 replace($filename)으로 호출하고 있지만 엄밀히 따지면 전체 패스를 줄 필요가 없습니다. 이미 디렉토리가 변경되어 있기 때문이죠. 이는 매우 편리할 수도, 그리고 매우 위험할 수도 있습니다. 프로그램을 작성할 때 위의 사항에 유의해야만 합니다.


[추가]

Aero 님께서 좋은 정보를 주셔서 찾아보니 CPAN의 설명에 no_chdir 이라는 옵션이 있더군요. 그래서 다음과 같이 바꾸어 보았습니다.

find( {wanted => \&traverse, no_chdir => 1 }, 'target'); 
sub traverse {

   my $filename = $_;  
  
   if( (-f $filename)  && ($File::Find::name =~ /\.c$/))
   {        
      replace( $filename); 
   }


그리고, 더불어 펄 사용자 모임에 있는 Tip 하나를 더 소개합니다. 경로에서 디렉토리와 파일 이름 분리라는 글인데요, Regular Expression을 이용한 멋진 방법이네요.

( $dir, $file ) = ( $srcfilename =~ m|^(.*/)(.*)$| );

Regular Expression의 Greedy 특성을 이용한 방법으로 정말 멋지게 동작합니다 ^^









0 Trackback, 3 Comment

TRACKBACK :: http://naratalk.com/trackback/273 관련글 쓰기

댓글을 달아 주세요

  1. Favicon of http://aero.dnip.net/blog BlogIcon aero  댓글주소  수정/삭제  댓글쓰기

    File::Find의 find함수에서 디렉토리를 안 바뀌게 하는 옵션도 있습니다.
    http://kldp.org/node/101006#comment-469299 를 참고하시면 될 듯.

    2008/12/17 14:04
  2. keedi  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. 유용한 글 잘 읽었습니다. :-) 정규표현식을 이용한 간단한 디렉터리 및 파일 분리도 좋지만 또 한편으로는 기본 모듈로 포함하고 있는(설치가 필요없는) File::Basename 가 제공하는 fileparse(), basename(), dirname()을 사용하면 운영체제 별로 신경쓰지 않아도 된다는 면에서 괜찮은 것 같습니다. 새해 복 많이 받으세요~ :-)

    2009/01/03 18:33

1  ... 50 51 52 53 54 55 56 57 58  ... 264 
다...... (264)
Computer/Programming (106)
Links (14)
책 읽는 즐거움 (7)
끄적임 (66)
즐거운 과학 나라 (7)
일본 (5)
Study (4)