If you're using the perl rename utility, try something like this:
find . -type f -execdir rename -n 's/\s*-\s*/./g; s/\s+/./g; s/somename//ig' {} +
The \s*-\s*
matches a -
surrounded by zero-or-more whitespace characters (i.e. a -
with optional whitespace). \s+
matches one-or-more whitespace characters.
You can add as many s/search/replace/
commands in the rename script as you like. Note, though, that you need to be careful about the order of execution - e.g. if you want to change "foo" to "bar" and "food" to "drink", then you need s/food/drink/
before s/foo/bar/
because the latter will change food
to bard
.
The command above is applied to ALL filenames. If some of the s/search/replace/
commands do not apply to a particular filename, it's not an error - that particular command is not applied (but others still are). Even so, you may need to run multiple find
commands using the -name
or -iname
predicate if you want some renames to only be applied to certain file names.
You can also use alternation if you want to change multiple words to the same replacement. e.g.
s/(somename|someothername|thisname|thatname)//ig
that changes all of them to the empty string (i.e. removes them). The /i
modifier makes it case-insensitive.
The -n
option from rename
is a dry-run option - it will only show what would be renamed, without actually renaming anything. Remove the -n
from the rename command when you've verified that it does what you want, and nothing that you don't want. If you want verbose output while renaming, replace the -n
with -v
.
from man rename
:
-v
, -verbose
Verbose: print names of files successfully renamed.
-n
, -nono
No action: print names of files to be renamed, but don't rename.
Note: The perl rename
utility will not rename a file if the new filename already exists. It has no built-in ability to add numbers to filenames in case of collision, but one of the best features of this rename is that you're not restricted to just simple operations like s/search/replace/
- you can run any perl code inside a rename script and it will rename the source filename to whatever $_
is changed to (operators like s///
or y//
implicitly modify $_
if an explicit variable name is not used. If you're new to perl
, there's a pretty good explanation of what $_
is at https://perlmaven.com/the-default-variable-of-perl).
That allows something like this (untested, but might work)
find . -type f -execdir rename -n '
s/\s*-\s*/./g;
s/\s+/./g;
s/somename//ig;
if (-f $_) {
my $num='001';
while (-f "$_.$num") {
$num=sprintf('%03i',++$num);
};
$_ = "$_.$num";
}' {} +
That should add a zero-padded 3-digit-wide number (i.e. from 001
to 999
) to the filename if it already exists. Change %03i
to %02i
in the sprintf if you want only two digits (01
to 99
). Or, if you don't expect any numbering of duplicate files to exceed 9
, change it to just my $num=1
, and then just $num++
inside the while loop with no sprintf()
.
with a little more work (by splitting the filename into "basename" and "extension" portions) the numbering could be inserted before the extension, rather than just appended to the end.
You can find out which version of rename
you have with the -V
option. e.g. on my Debian system rename
is the perl rename while rename.ul
is the util-linux rename:
$ rename -V
/usr/bin/rename using File::Rename version 0.20
$ rename.ul -V
rename.ul from util-linux 2.31.1
find
commands are complete, so none of them will run. btw, which version ofrename
do you have - the perl version of rename, or the one from util-linux? they are very different and not compatible with each other. Runrename -V
if you're not sure.