Tips in Action‎ > ‎기타‎ > ‎

하위 디렉토리까지 모두 검색하기

전종필

디렉토리를 읽는 방법에는 opendir, readdir, closedir를 같이 이용하는 방법과, glob 함수를 이용하는 방법 두 가지가 있습니다.
그러나, 그 디렉토리의 하위 디렉토리까지 모두 찾아서 읽으려면, 그 함수 외에도 좀 더 복잡한 논리를 첨가해야 합니다. 예를 들면 다음과 같은 방법이 있을 것입니다.

my $dir = '.'; # 또는 @ARGV로 받든지...

my @dirs = ( $dir );
while( $dir = shift @dirs ) {
	my @paths = glob("$dir/*");
	foreach my $f (@paths) {
		if( -d $f ) {
			push @dirs, $f;
		}
		else {
			# 뭔가 합니다.
			print "File : $f\n";
		}
	}
}
위 예제가 이해가 가지 않더라도 신경쓰지 마십시오. 지금 설명하고자 하는 것은 위 예제가 아닙니다. 물론, 위처럼 해도 되지만, 굳이 일을 복잡하게 할 필요는 없습니다. 실용적으로 해야지요. File::Find 모듈을 사용하면 간단하게 해결됩니다.

use File::Find;
my $dir = '.'; # 또는 @ARGV로 받든지...

find(\&print_if_file, $dir);

sub print_if_file {
	if( -f $_ ) {
		print "File : $File::Find::name\n";
	}
}
결과는 같지만 훨씬 간결합니다. File::Find 모듈을 사용(use)하고, 그 모듈에서 정의된 find 함수를 호출하면서 첫번째 인수로 각 파일혹은 디렉토리를 처리할 서브루틴의 리퍼런스를 넣어주고, 그 뒤로 전체 트리를 검색할 디렉토리들을 나열합니다. 그러면 find 함수는 모든 디렉토리들을 하위 디렉토리까지 찾아 가면서 각 파일 혹은 디렉토리 하나를 찾을 때 마다 인수로 받았던 서브루틴을 호출하면서 $_ 변수에 파일 혹은 디렉토리 이름을 저장합니다. 이 때, $File::Find::dir는 그 파일 혹은 디렉토리가 존재하는 디렉토리이고, $File::Find::name은 해당 파일/디렉토리의 경로를 나타냅니다. ("$File::Find::dir/$_"는 "$File::Find::name"과 같은 값을 갖습니다.)
이렇게 전체 경로를 검색하면, 그 목적이 불필요한 파일을 지우는 것이든, 특정한 파일들을 수정하기 위한 것이든, 손쉽고 간결하게 일을 처리할 수 있을 것입니다. 
Comments