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

Viewed 171

I have many files in a folder with the format '{galaxyID}-cutout-HSC-I-{#}-pdr2_wide.fits', where {galaxyID} and {#} are different numbers for each file. Here are some examples:

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

I want to change the format of all files in this folder to match the following:

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

namely, I want to take out "cutout", the second number, and "pdr2_wide" from each file name. I would prefer to do this in either Perl or Python. For my Perl script, so far I have the following:

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

which gives me the error message

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

I included the [-n] because I want to make sure the changes are what I want before actually doing it; either way, this is in a duplicated directory just for safety.

2 Answers

It looks like you are using the rename you get on Ubuntu (it's not the one that's on my ArchLinux box), but there are other ones out there. But, you've presented it oddly. The brackets around -n shouldn't be there and the ; ends the command.

The syntax, if you are using what I think you are, is this:

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

The Perl expression is the argument to the -e switch, and can be a simple substitution. Note that this expression is a string that you give to -e, so that probably needs to be quoted:

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

And, instead of doing this in one step, I'd do it in two:

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

There are other patterns that might make sense. Instead of taking away parts, you can keep parts:

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

I'd be inclined to use named captures so the next poor slob knows what you are doing:

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

From your description {galaxyID}-cutout-HSC-I-{#}-pdr2_wide.fits, I assume that cutout-HSC-I is fixed.

Here's a script that will do the rename. It takes a list of files on stdin. But, you could adapt to take the output of 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");
        }
    }
}

For your sample input file, here's the program output:

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

The above is how I usually do things but here's one with just a regex. It's fairly strict in what it accepts [for safety], but you can adapt as desired:

#!/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");
        }
    }
}
Related