Ubuntu – Rename files to be capitalised but not impact on file extensions

batch-renamecommand linerename

I am using this on a customer's directory to rename files with first letter of each word being capitalised as per their request:

rename 's/\b(\w)/\u$1/g' *

That works fine, but it also capitalises the first letter of the extension, so I use this to fix that:

rename 's/\.Txt$/.txt/' *.Txt

which works okay if most of the files in a folder are the same extension (generally true),but is a pain if they are very mixed.

To get around that issue, I created a small script that looks like this (don't laugh!):

#!/bin/bash
rename 's/\.Txt$/.txt/' *.Txt
rename 's/\.Doc$/.doc/' *.Doc
rename 's/\.Docx$/.docx/' *.Docx
...
rename 's/\.Xlsx$/.xlsx/' *.Xlsx

I ignore the 'Can't rename *.Txt *.txt: No such file or directory' errors, and if I find an extension that is missing, I just add that line to my script.

I don't think this will matter, but the files are on a Windows server fileshare, but I am accessing it using Ubuntu 16.04LTS. If it does matter, then I could copy them to my local drive first, run a command in Ubuntu, then move the files back if required.

Is there any way to amend the first rename command to ignore the extensions and leave them as lowercase? Can I run the new command in a higher level directory, and have it recurse through all the sub-directories?

Best Answer

One way to achieve this might be to use Negative Lookbehind to only match the word-boundary - word character sequence when it is not preceded by a literal period e.g. given

$ ls
alan's file.txt  bar.txt  foo

then

$ rename -n 's/(?<!\.)\b\w*/\u$&/g' *
rename(alan's file.txt, Alan'S File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

Assuming you also want to avoid capitalizing the pluralizing s as well, we might modify that to

$ rename -n 's/(?<![.'\''])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

or even

$ rename -n 's/(?<![[:punct:]])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)