oksage
oksage

Reputation: 33

Recursively rename files to remove dots but leave extension unchanged

I've got a number of folders (80?) with files in them. Some of the filenames have multiple dots (file.name.ext). With the 'find' command being recursive, I'm able to rename the filenames within the folders from uppercase to lowercase:

find . -type f -execdir rename 'y/A-Z/a-z/' {} \;

Where 'find .' indicates to search the current folder. Where 'type f' searches only for files. Where 'execdir' executes the subsequent command on the output.

To do the same (uppercase to lowercase), but for the folders, both of these work:

rename 'y/A-Z/a-z/' *

rename 'y/A-Z/a-z/' ./*

To remove the dots from the foldername, this works:

find . -maxdepth 1 -execdir sed 's/[.]/_/g' {} \;

edit:(actually this is not working for me now)

...

What fails is when I try to recursively remove the dots:

find . -type f -execdir rename 's/\.(?=[^.]*\.)/_/g' '{}' \;

I get the error:

Can't rename ./filename.ext _/filename.ext: No such file or directory

I've also tried to add -printf "%f\n" to remove the leading ./ :

find . -type f -printf "%f\n" -execdir rename  's|[.]|_|g; s|_([^_]*)$|.$1|' {} \;

which outputs the filename followed by the same error

file.name.ext
Can't rename ./file.name.ext _/file.name.ext: No such file or directory

Those commands above were run from the parent folder 'above' the 80 folders that contain the files, with the idea of doing a dryrun (rename -nono) on all the files within the 80 folders at once.

From within one of those 80 folders I can remove the dots from the filename, leaving the dot in the extension unchanged, with:

rename 's/\.(?=[^.]*\.)/_/g'

But I don't want to have to go into each of those many folders to run the command. What will work recursively to delete all dots, leaving the extension dot alone?

Upvotes: 1

Views: 1195

Answers (1)

oksage
oksage

Reputation: 33

I found the answer here: Linux recursively replace periods for all directorys and all but last period for files with underscores

At first I didn't think it answered my specific question, but it actually does.

while IFS= read -rd '' entry; do
entry="${entry#./}"         # strip ./
if [[ -d $entry ]]; then
  rename 'y/A-Z/a-z/; s/ /_/g; s/\./_/g' "$entry"
else
  rename 'y/A-Z/a-z/; s/ /_/g; s/\.(?=.*\.)/_/g' "$entry"
fi
done < <(find . -iname '*' -print0)

Thanks to anubhava .

Upvotes: 1

Related Questions