如何以特定格式重命名文件夹中的多个文件?

How to rename multiple files in a folder with a specific format?

我在一个文件夹中有很多文件,格式为“{galaxyID}-cutout-HSC-I-{#}-pdr2_wide.fits”,其中 {galaxyID} 和 {#} 是每个文件的不同编号文件。以下是一些示例:

2185-cutout-HSC-I-9330-pdr2_wide.fits
992-cutout-HSC-I-10106-pdr2_wide.fits
2186-cutout-HSC-I-9334-pdr2_wide.fits

我想更改此文件夹中所有文件的格式以匹配以下内容:

2185_HSC-I.fits
992_HSC-I.fits
2186_HSC-I.fits

即,我想从每个文件名中取出“cutout”、第二个数字和“pdr2_wide”。我更愿意在 Perl 或 Python 中执行此操作。对于我的 Perl 脚本,到目前为止我有以下内容:

rename [-n];
    my @parts=split /-/;
    my $this=$parts[0].$parts[1].$parts[2].$parts[3].$parts[4].$parts[5];
    $_ = $parts[0]."_".$parts[2]."_".$parts[3];
    *fits

这给了我错误信息

Not enough arguments for rename at ./rename.sh line 3, near "];" Execution of ./rename.sh aborted due to compilation errors.

我加入了 [-n] 是因为我想在实际执行之前确保所做的更改是我想要的;无论哪种方式,为了安全起见,它都在一个重复的目录中。

根据你的描述 {galaxyID}-cutout-HSC-I-{#}-pdr2_wide.fits,我认为 cutout-HSC-I 是固定的。

这是一个可以重命名的脚本。它需要 stdin 上的文件列表。但是,您可以适应 readdir:

的输出
#!/usr/bin/perl

master(@ARGV);
exit(0);

sub master
{
    my($oldname);

    while ($oldname = <STDIN>) {
        chomp($oldname);

        # find the file extension/suffix
        my($ix) = rindex($oldname,".");
        next if ($ix < 0);

        # get the suffix
        my($suf) = substr($oldname,$ix);

        # only take filenames of the expected format
        next unless ($oldname =~ /^(\d+)-cutout-(HSC-I)/);

        # get the new name
        my($newname) =  . "_" .  . $suf;

        printf("OLDNAME: %s NEWNAME: %s\n",$oldname,$newname);

        # rename the file
        # change to "if (1)" to actually do it
        if (0) {
            rename($oldname,$newname) or
                die("unable to rename '$oldname' to '$newname' -- $!\n");
        }
    }
}

对于示例输入文件,程序输出如下:

OLDNAME: 2185-cutout-HSC-I-9330-pdr2_wide.fits NEWNAME: 2185_HSC-I.fits
OLDNAME: 992-cutout-HSC-I-10106-pdr2_wide.fits NEWNAME: 992_HSC-I.fits
OLDNAME: 2186-cutout-HSC-I-9334-pdr2_wide.fits NEWNAME: 2186_HSC-I.fits

以上是我通常做事的方式,但这里只有一个正则表达式。 [出于安全考虑],它接受的内容相当严格,但您可以根据需要进行调整:

#!/usr/bin/perl

master(@ARGV);
exit(0);

sub master
{
    my($oldname);

    while ($oldname = <STDIN>) {
        chomp($oldname);

        # only take filenames of the expected format
        next unless ($oldname =~ /^(\d+)-cutout-(HSC-I)-\d+-pdr2_wide([.].+)$/);

        # get the new name
        my($newname) =  . "_" .  . ;

        printf("OLDNAME: %s NEWNAME: %s\n",$oldname,$newname);

        # rename the file
        # change to "if (1)" to actually do it
        if (0) {
            rename($oldname,$newname) or
                die("unable to rename '$oldname' to '$newname' -- $!\n");
        }
    }
}

看起来您正在使用 Ubuntu 上的 rename(它不是我的 ArchLinux 盒子上的那个),但还有其他的。但是,你的表现很奇怪。 -n 周围的括号不应该存在,; 结束命令。

语法,如果你使用的是我认为的,是这样的:

% rename -n -e PERL_EXPR file1 file2 ...

Perl 表达式是 -e 开关的参数,可以是一个简单的替换。请注意,此表达式是您提供给 -e 的字符串,因此可能需要引用:

% rename -n -e 's/-\d+-pdr2_wide//' *.fits
rename(2185-cutout-HSC-I-9330-pdr2_wide.fits, 2185-cutout-HSC-I.fits)

而且,我不会一步完成,而是分两步完成:

% rename -n -e 's/-cutout-/-/; s/-\d+-pdr2_wide//' *.fits
rename(2185-cutout-HSC-I-9330-pdr2_wide.fits, 2185-HSC-I.fits)

还有其他可能有意义的模式。你可以保留零件,而不是拿走零件:

% rename -n -e 's/\A(\d+).*(HSC-I).*/-.fits/' *.fits
rename(2185-cutout-HSC-I-9330-pdr2_wide.fits, 2185-HSC-I.fits)

我倾向于使用命名捕获,以便下一个可怜的懒汉知道你在做什么:

% rename -n -e 's/\A(?<galaxy>\d+).*(HSC-I).*/$+{galaxy}-.fits/' *.fits
rename(2185-cutout-HSC-I-9330-pdr2_wide.fits, 2185-HSC-I.fits)