How to rename multiple files using find

The following is a direct fix of your approach:

find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;

However, this is very expensive if you have lots of matching files, because you start a fresh shell (that executes a mv) for each match. And if you have funny characters in any file name, this will explode. A more efficient and secure approach is this:

find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed

It also has the benefit of working with strangely named files. If find supports it, this can be reduced to

find . -type f -name 'file*' -exec mv {} {}_renamed \;

The xargs version is useful when not using {}, as in

find .... -print0 | xargs --null rm

Here rm gets called once (or with lots of files several times), but not for every file.

I removed the basename in you question, because it is probably wrong: you would move foo/bar/file8 to file8_renamed, not foo/bar/file8_renamed.

Edits (as suggested in comments):

  • Added shortened find without xargs
  • Added security sticker

After trying the first answer and toying with it a little I found that it can be done slightly shorter and less complex using -execdir:

find . -type f -name 'file*' -execdir mv {} {}_renamed ';'

Looks like it should also do exactly what you need.


Another approach is to use a while read loop over find output. This allows access to each file name as a variable that can be manipulated without having to worry about additional cost / potential security issues of spawning a separate sh -c process using find's -exec option.

find . -type f -name 'file*' |
    while IFS= read file_name; do
        mv "$file_name" "${file_name##*\/}_renamed"
    done

And if the shell being used supports the -d option to specify a read delimiter you can support strangely named files (e.g. with a newline) using the following:

find . -type f -name 'file*' -print0 |
    while IFS= read -d '' file_name; do
        mv "$file_name" "${file_name##*\/}_renamed"
    done

Tags:

Shell

Find