Recursively rename files (change extension) in Linux
How do I rename all files in a directory, recursively, changing one file extension to another, for thousands of files in thousands of subfolders? I see a lot of commands that do almost what I want, but not quite.
find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."
...
rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile
Figured it out
find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile
of course remove the -v when actually doing it, or it will waste time displaying all the files
With zsh:
autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'
Remove the -n
to actually perform the renaming.
Something like:
find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
Explanation
The above starts walking the directory tree starting at the current working directory (.
). Every time a file name matches the pattern *.andnav
(e.g., foo.andnav
) the following command is executed:
sh -c 'mv "$0" "${0%.andnav}.tile"' foo.andnav
Where $0
is foo.andnav
and ${0%.andnav}.tile
replaces the .andnav
suffix with .tile
so basically:
mv foo.andnav foo.tile
I found this method is easier and easier to read:
find . -name "*.andnav" | rename "s/\.andnav$/.tile/"
At least on Ubuntu derivations rename takes a list of files from STDIN if none are on the command line. And this can be tested easily with:
find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"
until you get it right.