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

时间:2021-01-10 18:59:40

标签: perl rename

我在一个文件夹中有许多文件,格式为“{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] 是因为我想在实际执行之前确保更改是我想要的;不管怎样,为了安全起见,这是在一个重复的目录中。

2 个答案:

答案 0 :(得分:2)

看起来您正在使用在 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).*/$1-$2.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}-$2.fits/' *.fits
rename(2185-cutout-HSC-I-9330-pdr2_wide.fits, 2185-HSC-I.fits)

答案 1 :(得分:1)

根据您的描述 {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) = $1 . "_" . $2 . $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) = $1 . "_" . $2 . $3;

        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");
        }
    }
}
相关问题