[Perl] 파일 이름 바꾸는 스크립트 (정규식 사용, 디렉토리 사용 가능)
Perl의 창시자인 Larry Wall이 Perl 책을 쓰던 시절에 그때부터 책에 수록되어 있었던 rename 스크립트가 있다. Perl 프로그래머라면 다들 알 지도 모르겠다.
요즘 어떤 리눅스 배포본에는 rename인지 rename.pl인지 하는 이름의 스크립트로 기본 설치가 되기도 하는 것 같다. (이건 확실하지 않다.)
정규식을 이용해서 편하게 이름 변환 규칙을 지정할 수 있다는 게 장점이다.
예를 들면, .doc 확장자를 가진 파일을 .txt로 변환한다고 하면, shell에서 for loop를 돌려서 매 파일마다 파일 이름 부분과 확장자 부분을 분리해서 확장자 부분만 바꿔치기하는 귀찮은 작업을 해줘야 한다. 하지만 rename.pl로 하면?
rename.pl 's/\.doc$/\.txt/' *.doc
이렇게 하면 된다. .doc로 끝나는 문자열이 있으면 그 부분을 .txt로 바꾸겠다는 의미이다.
이 스크립트을 아주 유용하게 잘 써왔는데, 파일이 상당히 많은 디렉토리에서 이 작업을 하면 몇 가지 단점이 나타난다. 일단 *.doc처럼 여러 파일을 지정할 경우, shell에 따라 argument 수가 너무 많아서 실행이 불가능한 경우가 있고, 또한 Perl인 점을 감안하더라도 속도가 너무 느리다. 그래서 디렉토리에 대해서 일괄 처리가 가능하도록 수정해봤다.
#!/usr/bin/env perl # # Usage: rename perlexpr [files or directory] # # updated by terzeron@gmail.com, 2009/10/07 # copied and updated by terzeron@indra.snu.ac.kr, 1997/09/20 use strict; use English; sub rename_file { my $pattern = shift; my $file = shift; my $dir = shift; my $old_name = "$dir/$file"; $_ = $old_name; eval $pattern; my $new_name = $_; #$old_name =~ s/([\?\&\*])/\\$1/og; print "$old_name -> $new_name\n"; if ($old_name ne $new_name) { if (not rename($old_name, $new_name)) { print "can't rename $old_name to $new_name, $ERRNO\n"; return -1; } } return 0; } sub main { # If no perlexpr argument exists, exit. if (scalar @ARGV < 2) { print STDERR "Usage:\t$PROGRAM_NAME\t \n"; return -1; } my $pattern = shift @ARGV; if (scalar @ARGV == 1 and -d $ARGV[0]) { # directory my $dir; if (not opendir($dir, $ARGV[0])) { print STDERR "can't open directory '$dir' for reading, $ERRNO\n"; return -1; } while ((my $file = readdir($dir))) { if ($file eq "." or $file eq "..") { next; } if (rename_file($pattern, $file, $ARGV[0]) < 0) { return -1; } } closedir($dir); } else { # file list foreach my $file (@ARGV) { if (rename_file($pattern, $file, "") < 0) { return -1; } } } } main();
이렇게 쓸 수 있다.
rename.pl 's/\.doc$/\.txt/' /home/terzeron/doc_dir
이렇게 쓰면 좀 더 빠르게 실행될 것이다.
rename.pl 's/\.doc$/\.txt/o' /home/terzeron/doc_dir
o modifier는 정규식을 compile하도록 지정하는 것이다. compile해놓고 여러 파일에 적용하면 빠르게 동작한다.
댓글 2개
aero
정규식의 o modifier는 obsolete된 feature로 perl 5.6이후에서는 자동으로 최적화 되므로 정규식에 변수가 들어갈 경우가 아니면(변수는 변하더라도 처음 한번만 컴파일을 의미)명시적으로 쓸 필요가 없습니다.그리고 컴파일된 정규식을 원하면 o modifier보다 qr을 쓰기를 추천한다고 합니다.
http://stackoverflow.com/questions/550258/does-the-o-modifier-for-perl-regular-expressions-still-provide-any-benefit
terzeron
안녕하세요?
테스트해보니 말씀해주신 것처럼 o modifier를 쓰지 않아도 compile되는군요. 수행 속도도 동일하구요. 다만 perlre나 perlreref를 문서를 봐도 여전히 o modifier가 나와 있고 backward compatibility에 대한 언급이 없어서 그걸 써야 하는 줄 알고 있었습니다.
알려주셔서 감사합니다.