2011-12-09 6 views
7

디렉토리를 가져 가고 모든 이메일 (* .msg) 파일에 대해 처음부터 'RE'를 제거하고 싶습니다. 다음 코드가 있지만 이름 바꾸기가 실패합니다.Perl을 사용하여 디렉토리의 파일 이름 바꾸기

opendir(DIR, 'emails') or die "Cannot open directory"; 
@files = readdir(DIR); 
closedir(DIR); 

for (@files){ 
    next if $_ !~ m/^RE .+msg$/; 
    $old = $_; 
    s/RE //; 
    rename($old, $_) or print "Error renaming: $old\n"; 
} 
+4

당신은 무엇이 잘못의 아이디어를 얻을 수있는 오류 ($!)를 인쇄하는 경우 ... – pilcrow

+0

그 지적 주셔서 감사합니다. 오류는 'No such file or directory'입니다. 나는 $ old 파일 이름이 정확하기 때문에 놀랍다. – Johnathan1

+2

'rename '은 플랫폼 간 지원을 즐기지 않는 반면,'File :: Copy'의'move' 함수는 @Zaid : – Zaid

답변

9

당신의 ./emails 디렉토리에이 파일이 포함 된 경우 :

1.msg 
2.msg 
3.msg 

다음 @files 이름을 바꾸기 전에 ('.', '..', '1.msg', '2.msg', '3.msg')하지만 rename 같은 것을 chdir 할 수 있도록 'emails/1.msg' 같은 이름, 'emails/2.msg' 등을 원하는 모양 :

chdir('emails'); 
for (@files) { 
    #... 
} 

아마도 ch chdir 반환 값도 확인하십시오.

또는 추가 디렉토리 이름 자신을 :

rename('emails/' . $old, 'emails/' . $_) or print "Error renaming $old: $!\n"; 
# or rename("emails/$old", "emails/$_") if you like string interpolation 
# or you could use map if you like map 

당신은 grep를 사용하여 디렉토리의 읽기 및 필터링을 결합 할 수 있습니다 :

my @files = grep { /^RE .+msg$/ } readdir(DIR); 

또는이 :

opendir(DIR, 'emails') or die "Cannot open directory"; 
for (grep { /^RE .+msg$/ } readdir(DIR)) { 
    (my $new = $_) =~ s/^RE //; 
    rename("emails/$_", "emails/$new") or print "Error renaming $_ to $new: $!\n"; 
} 
closedir(DIR); 
+0

우수. 이걸 설명해 주셔서 감사합니다. – Johnathan1

5

당신을가 아닌 glob과 같은 행동을 가정하는 것으로 보입니다.과 같은 동작.

readdir 시스템 호출은 디렉토리 내의 파일 이름만을 반환하며 ...의 두 항목을 포함합니다. 이것은 Perl의 readdir 함수로 전달되며, mu의 대답에 대해 좀 더 자세하게 설명합니다.

어쨌든 배열의 모든 결과를 수집하는 경우 readdir을 사용하면 별다른 의미가 없습니다.

@files = glob('emails/*'); 
+0

+1은 'glob'이 있음을 상기시켜줍니다. 'glob'의 단점은''emails/''접두어가 있기 때문에 약간의 이름 변경이 복잡해진다는 것입니다. 이것은 꽤 사소한 문제이며 다루기는 쉽지 않습니다. –

2

이미 언급했듯이 예상되는 경로 때문에 스크립트가 실패하고 스크립트 사용이 동일하지 않습니다.

나는 더 투명한 사용법을 제안합니다. 디렉토리 하드 코딩은 좋은 생각이 아닙니다. 언젠가 내가 원본 파일을 수정하기 위해 스크립트를 만들 때 배웠던 것처럼 하드 코딩 된 경로와 내 동료가이 복사본을 변경하기 위해 빌려주는 멋진 스크립트라고 생각했습니다. 너!

용도 :

perl script.pl "^RE " *.msg 

정규식 즉, 예를 들면 경로 스크립트 관련 나타낸다 후 파일 글롭리스트, *.msg, emails/*.msg 또는 심지어 /home/pat/emails/*.msg /home/foo/*.msg. (복수 glob 가능)

절대 경로를 사용하면 사용자가 어떤 파일에 영향을 미치는지 의심의 여지가 없으며 스크립트를 재사용 할 수도 있습니다.

코드 :

use strict; 
use warnings; 
use v5.10; 
use File::Copy qw(move); 

my $rx = shift; # e.g. "^RE " 

if ($ENV{OS} =~ /^Windows/) { # Patch for Windows' lack of shell globbing 
    @ARGV = map glob, @ARGV; 
} 

for (@ARGV) { 
    if (/$rx/) { 
     my $new = s/$rx//r; # Using non-destructive substitution 
     say "Moving $_ to $new ..."; 
     move($_, $new) or die $!; 
    } 
} 
+0

+1 : Windows의 Unix-ification을 좋아해야합니다. – Zaid

+0

안녕하세요, 저는이 아이디어를 정말 좋아합니다. 줄에 오류가 발생하는 것 같습니다. $ new = s/$ rx // r. 출력은 's/$ rx // r'근처에서 연산자가 예상되는 곳에 bareword가 있으며 – Johnathan1

+0

@JP와 비슷한 구문 오류가 있습니다. 오, 그건 당신 perl 버전 때문일 수 있습니다 .. 어떤 버전을 사용합니까? – TLP

관련 문제