Using rename, keeping part of the search regex

Morning,

The current project I have to work on had a previous naming scheme that bothers me...

Base.v2.c
Base.v2a.c
Slider.v4a.h
Area.v2a.2.h

I have been told the "a" in the version was to identify "alpha" versions that needed more work. At this stage in the project I can remove the "a" and replace it with a ".1" (v2a -> v2.1).

There are a lot of files, beyond what I am willing to do manually.

I know I could use the rename command to rename all the files at once, but I am running into an issue with how to do that. If I use something like:

rename 's/[0-9]a/.1/' *

then I will lose the last digit of the version number. Is there any way to have rename (or another command line tool) remember part of the regex used to find the file? So that '[0-9]a' to '[0-9].1' would change 1a to 1.1, and 4a to 4.1, etc.


Solution 1:

You can either use capture groups:

$ rename -n 's/(\d)a/$1.1/' *
Area.v2a.2.h -> Area.v2.1.2.h
Base.v2a.c -> Base.v2.1.c
Slider.v4a.h -> Slider.v4.1.h

Or you can use a lookbehind:

$ rename -n 's/(?<=\d)a/.1/' *
Area.v2a.2.h -> Area.v2.1.2.h
Base.v2a.c -> Base.v2.1.c
Slider.v4a.h -> Slider.v4.1.h

Or, similar to a lookbehind, the 0-length assertion \K, which means "forget everything matched until this point":

$ rename -n 's/\d\Ka/.1/' *
Area.v2a.2.h -> Area.v2.1.2.h
Base.v2a.c -> Base.v2.1.c
Slider.v4a.h -> Slider.v4.1.h

Note that I used the shorter \d instead of [0-9]. The two are equivalent, but rename is a perl script, so understands the syntax of Perl Compatible Regular Expressions (PCRE).

Note that this will only change the first occurrence of a number followed by an a. This may or may not be what you need, depending on your file names.

The -n makes rename show what it would do without actually doing anything. once you've confirmed that it works as expected, remove it to actually change the file names.

Solution 2:

Modify the command in this way:

rename 's/([0-9])a/$1.1/' *
  • The substitution command s/<souce>/<replacement>/ will replace the source string (that could be a regular expression) with the replacement string.
  • The capture groups - the parts of the source string that are enclosed with brackets: (regexp), (string), etc. will be assigned as values of successive variables: $1, $2, etc..
  • So, within the replacement string, the variable $1 will be expanded with its value, that in this case must matches with the regexp [0-9].