Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash rename extension recursive

I know there are a lot of things like this around, but either they don't work recursively or they are huge.

This is what I got:

find . -name "*.so" -exec mv {} `echo {} | sed s/.so/.dylib/` \;

When I just run the find part it gives me a list of files. When I run the sed part it replaces any .so with .dylib. When I run them together they don't work.

I replaced mv with echo to see what happened:

./AI/Interfaces/C/0.1/libAIInterface.so ./AI/Interfaces/C/0.1/libAIInterface.so

Nothing is replaced at all!
What is wrong?

like image 658
Pepijn Avatar asked Jan 31 '10 14:01

Pepijn


1 Answers

This will do everything correctly:

find -L . -type f -name "*.so" -print0 | while IFS= read -r -d '' FNAME; do
    mv -- "$FNAME" "${FNAME%.so}.dylib"
done

By correctly, we mean:

1) It will rename just the file extension (due to use of ${FNAME%.so}.dylib). All the other solutions using ${X/.so/.dylib} are incorrect as they wrongly rename the first occurrence of .so in the filename (e.g. x.so.so is renamed to x.dylib.so, or worse, ./libraries/libTemp.so-1.9.3/libTemp.so is renamed to ./libraries/libTemp.dylib-1.9.3/libTemp.so - an error).

2) It will handle spaces and any other special characters in filenames (except double quotes).

3) It will not change directories or other special files.

4) It will follow symbolic links into subdirectories and links to target files and rename the target file, not the link itself (the default behaviour of find is to process the symbolic link itself, not the file pointed to by the link).

like image 156
aps2012 Avatar answered Sep 16 '22 14:09

aps2012