How to batch rename sequentially prefixed numbers to new sequential prefixes via terminal?

How can I batch rename, using the terminal, a set of files where multiple numbers share the same prefix so that all those prefixes are set to new ones?

For example:

011.foo.txt   -> 001.foo.txt
011.bar.psd   -> 001.bar.psd
011.baz.gif   -> 001.baz.gif
012.qux.js    -> 002.qux.js
012.corge.png -> 002.corge.png
...
020.thud.txt  -> 010.thud.txt

I'd like to use the rename command if possible:

rename [ -h|-m|-V ] [ -v ] [ -0 ] [ -n ] [ -f ] [ -d ] [ -e|-E perlexpr]*|perlexpr [ files ]

Really appreciate your help figuring this out, Thanks!


Using the perl rename as requested.

For what your question demonstrates:

rename -n 's/^(\d+)/sprintf "%03d", $1-10/e' *

dry-run output:

rename(011.bar.psd, 001.bar.psd)
rename(011.baz.gif, 001.baz.gif)
rename(011.foo.txt, 001.foo.txt)
rename(012.corge.png, 002.corge.png)
rename(012.qux.js, 002.qux.js)
rename(020.thud.txt, 010.thud.txt)

For what the question title says, with actual sequential prefixes:

rename -n -E 'use vars q{$n}' -e 's/^(\d+)/sprintf "%03d", ++$n/e' *
rename(011.bar.psd, 001.bar.psd)
rename(011.baz.gif, 002.baz.gif)
rename(011.foo.txt, 003.foo.txt)
rename(012.corge.png, 004.corge.png)
rename(012.qux.js, 005.qux.js)
rename(020.thud.txt, 006.thud.txt)

For the first one, if you don't want to hardcode the delta 10:

rename -n -E 'use vars q{$delta}' -e '
    s{^(\d+)}{
        $delta = $1 - 1 unless defined $delta;
        sprintf "%03d", $1 - $delta
    }e
' *

If you want files with the same original prefix to map to the same prefix in the new scheme without relying on subtraction, then you could do so by creating a hash (associative array) of the prefixes, numbering those sequentially, then performing the rename substitutions by lookup in the hash. Ex.

$ rename -n -E '
  BEGIN {
    my $n = 1;
    our %pfxs;
    foreach my $f (@ARGV) {
      $pfxs{$1} = (exists $pfxs{$1} ? $pfxs{$1} : $n++) if $f =~ /^(\d{3})/
    }
  }
  our %pfxs;
  s/^(\d{3})/sprintf "%03d", $pfxs{$1}/e
' [0-9][0-9][0-9].*
rename(011.bar.psd, 001.bar.psd)
rename(011.baz.gif, 001.baz.gif)
rename(011.foo.txt, 001.foo.txt)
rename(012.corge.png, 002.corge.png)
rename(012.qux.js, 002.qux.js)
rename(020.thud.txt, 003.thud.txt)

Since it doesn't rely on subtraction, this method can be used even when the original prefixes are non-numeric.

This can undoubtedly be improved - in particular, one could check the max value of $n at the end of the mapping and choose the width of the output accordingly.