biximilien
biximilien

Reputation: 23

Fixing a few thousands filenames on linux

I have extracted clips from a video with ffmpeg, following this pattern 'clip-%4d.png'.

This has yielded files like: clip-0001.png, clip-0002.png and so on.

I have then applied many filters with imagemagick "convert" to those pictures, and it ran for a couple hours.

I realised my list order is broken after clip-9999.png, it becomes clip-10000.png and up to clip-40000.png, successfully ruining my sequence of clips.

I would like to convert all my clips to follow the sequence clip-00000.png, clip-00001.png up to clip-40000.png.

I could restart the whole process using pattern 'clip-%5d', but I am told rename utility might solve my problem; however I am myself quite unfamiliar with regular expressions.

Upvotes: 2

Views: 391

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 753525

Using a Perl-based rename command

If you've got a Perl-based rename command, that's pretty easy:

rename 's/(\d{4})/0$1/' *-????.png

I note in passing that if you've really got about 10,000 clips to rename, you may need to work with xargs or find to avoid problems with 'argument list too long'.

find . -name 'clip-????.png' -exec rename 's/(\{4})/0$1/' {} +

or:

find . -name 'clip-????.png' -print | xargs rename 's/(\d{4})/0$1/'

Since your names don't contain spaces, either will work. If there are spaces to worry about, use the find-only variant, assuming your find supports the POSIX 2008 + notation to find. This can be applied to any of the other answers with a little care.

I note that this Perl script avoids having to execute mv 10,000 times, so it is likely to outpace any of the shell scripts that executes mv for each file rename. For a one-off exercise, this may not matter, but it will become more of an issue when you get to more than 100,000 clips.

Also, the script below has the option to read the file names, one per line, but it slurps the whole lot into memory, which isn't dreadfully efficient (but was present in the original version of the script and has been kept, even though I've hardly ever used the option). Assuming a sane modern machine (say 1 GiB of memory, but less would be sufficient), that is not going to be a problem with just 10,000 names of length 12 characters each. So you could also use:

find . -name 'clip-????.png' -print | rename 's/(\d{4})/0$1/'

A Perl-based rename script

If you've not got a Perl-based rename command, this is the one I use. It was originally from the 1st Edition of the Camel Book, but has been modified a little over the years:

#!/usr/bin/env perl
#
# @(#)$Id: rename.pl,v 1.8 2011/06/03 22:30:22 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use warnings;
use Getopt::Std;

my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
    printf "%s\n", q'RENAME Version $Revision: 1.8 $ ($Date: 2011/06/03 22:30:22 $)';
    exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV)
{
    if (-e $_ || -l $_)
    {
        my($was) = $_;
        eval $op;
        die $@ if $@;
        next if ($was eq $_);
        if ($force == 0 && -f $_)
        {
            print STDERR "rename failed: $was - $_ exists\n";
        }
        else
        {
            print "+ $was --> $_\n" if $trace;
            print STDERR "rename failed: $was - $!\n"
                unless ($noexc || rename($was, $_));
        }
    }
    else
    {
        print STDERR "$_ - $!\n";
    }
}

Upvotes: 2

Vijay
Vijay

Reputation: 67211

you can check here:

you can replace the command gsub(/-\(.*\)/,"",$0); in the link with

gsub(/-/,"-0",$0);

and the ls -1 part will be replaced with ls -1 clip-????.png also you need to remove the search part in the awk command. I tested below with a sample file.

@jonathan,I did not really understand what you said.But below is test i made:

> ls -1 clip-????.png
clip-0003.png
clip-1111.png

> ls -1 clip-????.png | nawk '{old=$0;gsub(/-/,"-0",$0);system("mv \""old"\" "$0)}'
phoenix.332> ls -1 clip-?????.png
clip-00003.png
clip-01111.png
> ls -1 clip-????.png
ls: No match.

nawk is on solaris . you can use awk for other flavours of unix.

Upvotes: 0

Emanuele Paolini
Emanuele Paolini

Reputation: 10162

Use this command in bash:

for file in clip-????.png ; do
    mv ${file} clip-0${file#clip-}
done

to check that the command will do the right thing, replace "mv" with "echo mv" to see the list of renamings that will be done.

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409146

You could do something like this:

for f in clip-[0-9][0-9][0-9][0-9].png; do mv $f `echo $f | sed 's/clip-/clip-0/'`; done

Note: To test without actually doing anything, replace mv with echo mv.

Upvotes: 2

Related Questions