This question already has an answer here:

I have a lot of directories. Each one of these has a file with a specific extension .ext.

I want to rename these files.


// Note: The names are random, can have spaces and special characters

 |- First Directory
 |   |
 |   |- Some file.txt
 |   |- Another one.pdf
 |   `- The one to rename.ext
 |- Second Directory
 |   |
 |   |- Some file.txt
 |   |- Another one.pdf
 |   `- The one to rename.ext

I want to rename all the file with the .ext extension to new name.ext2. There is only one file with the .ext per directory, so no problem with that.

What I have done so far is:

find ./Parent -name "*.ext" -exec mv "{}" "{}.ext2" \;

And I get a bunch of The one to rename.ext.ext2, I am stuck about renaming them new name.ext2. If I just set it as the second argument of mv, it will move them into the Parent directory, and thus, each call to the mvfunction will overwrite the previous moved file.

Note: I couldn't make it work using the -exec bash -c '' argument. I tried something along the lines of:

find ./Parent -name "*.ext" -exec bash -c 'mv {} "$(dirname {})/new name.ext2"' \;

But I get some issue with the $() being expanded before {}

marked as duplicate by Michael Homer, jasonwryan, Anthon, Shadur, Thomas Dickey Apr 28 '16 at 8:04

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    Also this one, which is a more similar question but with answers less applicable to what you're trying. – Michael Homer Apr 28 '16 at 5:47
  • I already searched on Google and the SE sites; I am asking because I still couldn't make it work after reading them. :-) – JoliG Apr 28 '16 at 5:50
  • This answer does exactly what you asked. – Michael Homer Apr 28 '16 at 5:53
  • If that specific part is your problem, the second candidate dupe is a better pairing (but all the answers are quite different approaches to what you've been trying and it doesn't match the title question as well). – Michael Homer Apr 28 '16 at 5:55
  • @MichaelHomer: Unfortunately, not all systems can call the shopt -s globstar nullglob command. (c.f. comment on this answer) It doesn't work on OSX and I can't upgrade bash. – JoliG Apr 28 '16 at 6:02

You can use the -printf function of find to construct your commands:

find /tmp -name "*.ext" -printf "mv %p %h/new_name.ext"
mv /tmp/foo.ext /tmp/new_name.ext

When you surround the command with $(), the commands will be executed:

$(find /tmp -name "*.ext" -printf "mv %p %h/new_name.ext")
find /tmp -name "*.ext"


The above command does not correctly work on multiple files and did not use quotes values. Use the below command instead:

find /tmp -name \*.ext\*
/tmp/dir with space/bar.ext

bash -x < <(find /tmp -name "*.ext" -printf "mv \"%p\" \"%h/new_name.ext2\"\n")
+ mv '/tmp/dir with space/bar.ext' '/tmp/dir with space/new_name.ext2'
+ mv /tmp/foo.ext /tmp/new_name.ext2

find /tmp -name \*.ext\*
/tmp/dir with space/new_name.ext2
  • After you change new_name.ext to new name.ext2 (what the question asks for), this will output mv Parent/First Directory/The one to rename.ext Parent/First Directory/new name.ext2 — without any quotes.  How well do you suppose that's going to work as a command? – G-Man Apr 28 '16 at 8:10

Use sed

for file in */*.ext; do
    ext2=`echo $file | sed 's/.ext/.ext2/'`
    mv $file $ext2
  • (1) For clarity, you might want to change `…` to $(…) — see this, this, and this.  (2) You should always quote your shell variable references (e.g., "$file" and "$ext2") unless you have a good reason not to, and you’re sure you know what you’re doing.  (3) This renames The one to rename.ext to The one to rename.ext2 — but the question calls for it to be renamed to new name.ext2.  (4) A safer sed command would be s/\.ext$/.ext2/.  The one you are using would change mytextfile.ext to my.ext2file.ext. – G-Man Apr 28 '16 at 8:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.