Использование Perl для переименования файлов в каталоге - PullRequest
7 голосов
/ 09 декабря 2011

Я бы хотел взять каталог и для всех файлов электронной почты (* .msg) удалить «RE» в начале.У меня есть следующий код, но переименовать не удается.

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";
}

Ответы [ 3 ]

9 голосов
/ 09 декабря 2011

Если ваша директория ./emails содержит следующие файлы:

1.msg
2.msg
3.msg

, тогда ваша @files будет выглядеть примерно как ('.', '..', '1.msg', '2.msg', '3.msg'), но ваша rename хочет иметь имена вроде 'emails/1.msg', 'emails/2.msg',и т.д. Таким образом, вы можете chdir перед переименованием:

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

Возможно, вы также захотите проверить возвращаемое значение 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);
5 голосов
/ 10 декабря 2011

Вы, похоже, предполагаете glob -подобное поведение, а не readdir -подобное поведение.

Базовый readdir системный вызов возвращаеттолько имена файлов в каталоге и будут включать две записи . и ...Это относится к функции readdir в Perl, просто для того, чтобы немного подробнее рассказать об ответе мю.

С другой стороны, нет смысла использовать readdir, если вы собираете все результаты вмассив в любом случае.

@files = glob('emails/*');
2 голосов
/ 10 декабря 2011

Как уже упоминалось, ваш сценарий не работает из-за ожидаемого пути, и сценарий не совпадает.

Я бы предложил более прозрачное использование.Жесткое кодирование каталога не очень хорошая идея, ИМО.Как я узнал однажды, когда я создал сценарий для изменения некоторых оригинальных файлов с жестко заданным путем, и мой коллега подумал, что это будет хороший сценарий для заимствования для изменения его копий.Упс!

Использование:

perl script.pl "^RE " *.msg

то есть регулярное выражение, затем список глобальных файлов, где путь обозначен относительно сценария, например, *.msg,emails/*.msg или даже /home/pat/emails/*.msg /home/foo/*.msg.(возможно несколько глобусов)

Использование абсолютных путей не оставит пользователю никаких сомнений относительно того, какие файлы он будет затрагивать, а также сделает скрипт многократно используемым.

Код:

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 $!;
    }
}
...