EDIT: Total rewrite of question for clarity.

I have a directory tree (new) with a bunch of files of with an extension of .new. I have an identical tree (old) where many of the files have names identical to those in the new tree except that the extension is .old. I would like to copy all of the .new files from the new directory tree into the old directory tree which contains the .old files. As a file with a .new extension is written into the old directory tree, I would like to delete any file with the same name but a .old extension.

So, if in the new directory tree, there is a file named new/foo/bar/file.new, it will be copied to the old directory tree as old/foo/bar/file.new and then the file old/foo/bar/file.old will be deleted if it exits.


This answer was hashed out below (using the old question that had extraneous background information that was confusing). See the actual solution that I worked out below as one of the answers.

  • 1
    I have not idea how to do that using bash commands only, but you could write a shell script (or even a one liner) around find, basename and unique. However the most practical solutions seems to be to run the conversion step (so that dir B has all the MP3 files and only the MP3 files), then delete dir A and rename (mv) dir B to dir A.
    – Hennes
    Commented Oct 27, 2013 at 18:11
  • The shell script is what I'm looking for (I don't really think there's a significant difference between a shell script and something for the command line), so I updated the problem to include scripts. Just deleting A and moving B will not verify that every flac in A was converted. Commented Oct 27, 2013 at 18:14
  • What do you have thus far?
    – slm
    Commented Oct 27, 2013 at 18:17
  • Nothing really. Commented Oct 27, 2013 at 18:18
  • 1
    @Pinyaka - Ask terdon or anyone else, it's not my way to be mean spirited about things such as this, sorry if it came across that way, but it's a bit frustrating to offer help and get pulled in different directions without a clear outline of what you're ultimately after.
    – slm
    Commented Oct 27, 2013 at 20:07

2 Answers 2


The basic approach would be to run this from the directory containing the mp3 files:

for i in *.mp3; do cp "$i" /path/to/flac/ && rm path/to/flac/"${i%.*}".flac; done

This goes through all files whose name ends in .mp3, copies each to /path/to/flac/ which should be the directory containing the flac files and if the copy was successful, deletes the corresponding .flac file. The trick is using the shell's string manipulation capabilities, ${i%.*} will remove the extension so rm ${i%.*}.flac will delete the file that has the same name as the current mp3 file but a .flac extension.

To illustrate:

$ foo='abc.def'
$ echo ${foo%.*}
  • I failed to mention in my example that the mp3 and flac directories are actually identical directory trees, so just using that for statement won't capture them. I'm going to mark the question as answered because you actually did answer the question that I asked, but I wonder if there's some way to make your one-liner to the same thing with a bunch of subdirectories. Commented Oct 27, 2013 at 19:02
  • 1
    @Pinyaka you could use the globstar option for recursive globbing. Set it with shopt -s globstar, and then you can use for f in ./**/*.mp3; ...; done.
    – evilsoup
    Commented Oct 27, 2013 at 19:59
  • I tried using the globstar mentioned above, but got a "bad substitution error. I still had the globstar option enabled when this command worked for me: for i in */*/*.mp3; do cp "$i" "path/to/flac/$i" && rm "/path/to/flac/${i//mp3/flac}";done Commented Oct 27, 2013 at 21:08

This was the final answer that got hashed out in the comments for terdons answer.

cd new
for i in */*/*.new; do cp "$i" "path/to/old/${i}" && rm "path/to/old/${i//new/old}"; done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .