使用 Perl 重命名目录中的文件

发布于 2024-12-20 11:19:25 字数 312 浏览 1 评论 0原文

我想要一个目录,对于所有电子邮件 (*.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";
}

I'd like to take a directory and for all email (*.msg) files, remove the 'RE ' at the beginning. I have the following code but the rename fails.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

握住我的手 2024-12-27 11:19:25

如果您的 ./emails 目录包含这些文件:

1.msg
2.msg
3.msg

那么您的 @files 将类似于 ('.', '..', '1.msg' , '2.msg', '3.msg') 但您的重命名想要像'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< 组合目录读取和过滤/code>

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);

If your ./emails directory contains these files:

1.msg
2.msg
3.msg

then your @files will look something like ('.', '..', '1.msg', '2.msg', '3.msg') but your rename wants names like 'emails/1.msg', 'emails/2.msg', etc. So you can chdir before renaming:

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

You'd probably want to check the chdir return value too.

Or add the directory names yourself:

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

You might want to combine your directory reading and filtering using grep:

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

or even this:

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);
心意如水 2024-12-27 11:19:25

您似乎假设 glob 类似的行为而不是 readdir 类似的行为。

底层的 readdir 系统调用仅返回目录中的文件名,并将包含两个条目 ...。这会延续到 Perl 中的 readdir 函数,只是为了提供有关 mu 答案的更多详细信息。

或者,如果您无论如何都要收集数组中的所有结果,那么使用 readdir 就没有多大意义。

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

You seem to be assuming glob-like behavior rather than than readdir-like behavior.

The underlying readdir system call returns just the filenames within the directory, and will include two entries . and ... This carries through to the readdir function in Perl, just to give a bit more detail on mu's answer.

Alternately, there's not much point to using readdir if you're collecting all the results in an array anyways.

@files = glob('emails/*');
黎歌 2024-12-27 11:19:25

正如已经提到的,您的脚本失败是因为您期望的路径和脚本使用的路径不同。

我建议采用更透明的用法。 IMO,对目录进行硬编码不是一个好主意。有一天,当我制作一个脚本来更改一些原始文件并使用硬编码路径时,我了解到,我的一位同事认为这是一个很好的脚本,可以借用来更改他的副本。哎呀!

用法:

perl script.pl "^RE " *.msg

即正则表达式,然后是文件全局列表,其中路径表示与脚本相关的路径,例如*.msgemails/*.msg< /code> 甚至 /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 $!;
    }
}

As already mentioned, your script fails because of the path you expect and the script uses are not the same.

I would suggest a more transparent usage. Hardcoding a directory is not a good idea, IMO. As I learned one day when I made a script to alter some original files, with the hardcoded path, and a colleague of mine thought this would be a nice script to borrow to alter his copies. Ooops!

Usage:

perl script.pl "^RE " *.msg

i.e. regex, then a file glob list, where the path is denoted in relation to the script, e.g. *.msg, emails/*.msg or even /home/pat/emails/*.msg /home/foo/*.msg. (multiple globs possible)

Using the absolute paths will leave the user with no doubt as to which files he'll be affecting, and it will also make the script reusable.

Code:

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 $!;
    }
}
独夜无伴 2024-12-27 11:19:25

我不知道正则表达式是否适合文件的指定名称,但是可以用一行代码来完成:

perl -E'for (){ ($new = $_) =~ s/(^RE)(.*$)/$2/; say $_." -> ".$new}

say ... 很适合测试,只需将其替换为 rename $_,$newrename($_,$new) )

  1. <*.*> 读取当前目录中的每个文件
  2. ($new = $_) = ~ 将以下替换保存在 $new 中并将 $_ 保持原样
  3. (^RE) 将此匹配项保存在 $1 中(可选),并仅匹配开头带有“RE”的文件
  4. (.*$ ) 保存所有内容,直到并包括该行的末尾 ($) ->将匹配项替换为 $2
  5. 中的字符串 $2

I don't know if the regex fits the specifig name of the files, but in one line this could be done with:

perl -E'for (</path/to/emails*.*>){ ($new = $_) =~ s/(^RE)(.*$)/$2/; say $_." -> ".$new}

(say ... is nice for testing, just replace it with rename $_,$new or rename($_,$new) )

  1. <*.*> read every file in the current directory
  2. ($new = $_) =~ saves the following substitution in $new and leaves $_ as intact
  3. (^RE) save this match in $1 (optional) and just match files with "RE" at the beginning
  4. (.*$) save everything until and including the end ($) of the line -> into $2
  5. substitute the match with the string in$2
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文