I have been digging through questions but can't seem to find the exact answer I need.

I have a directory with multiple subdirectories:

sent       sent.~16~  sent.~22~  sent.~29~  sent.~35~  sent.~41~  sent.~48~  sent.~54~  sent.~60~  sent.~67~  sent.~73~  sent.~8~
sent.~10~  sent.~17~  sent.~23~  sent.~3~   sent.~36~  sent.~42~  sent.~49~  sent.~55~  sent.~61~  sent.~68~  sent.~74~  sent.~80~
sent.~11~  sent.~18~  sent.~24~  sent.~30~  sent.~37~  sent.~43~  sent.~5~   sent.~56~  sent.~62~  sent.~69~  sent.~75~  sent.~81~
sent.~12~  sent.~19~  sent.~25~  sent.~31~  sent.~38~  sent.~44~  

Where each subdirectory holds a bunch of numbered files:

1.   11.  13.  15.  17.  4.  6.  8.
10.  12.  14.  16.  3.   5.  7.  9.

Essentially I would like to merge all these subdirectories into one directory, but not overwrite files with the same name. Will I need to change the name of files in each subdirectory to do this (ex: foo --> foo_~10~), and then merge all files to one subdirectory?

Is there an easy bash or shell script I can use for this? I have tried some variations of rsync, mv, and cp, but haven't quite gotten what I would like.


You can do this with a script like


mkdir merged
for dir in sent*
    cd "$dir"
    for file in *
        mv "$file" "$file"_"${dir#sent.}"
    mv * ../merged
    cd ..

if you want to rename each file according to the scheme in your question. If you'd like to rename them in such a way that their lexicographic order reflects in which folder the file was originally, just switch the order of the strings $file and ${dir#sent.}.

  • I think using <code> rsync "$dir/$file" $target/${file}_${dir} </code> would be better? The final "mv * ../merged and cd "$dir" and cd .. can be avoided – tpb261 Dec 9 '18 at 9:27
  • @tpb261 Good point. But then the inner for-loop would have to be for file in $dir/* which would require the mv-statement to be mv "$file" $target/${file#*/}_${dir#sent.} which would be uglier and would require an expansion of the variable target and the removal of the $dir/ from the file path once for every file in $dir, though this doesn't really add to the time, I guess. One the other hand, there is the mv * ../merged command in my script. I don't know what is more efficient, to be honest. – Stefan Hamcke Dec 9 '18 at 15:15
  • @tpb261 By the way, isn't rsync for copying, not for moving files? – Stefan Hamcke Dec 9 '18 at 15:18
  • Agreed. The mv becomes a bit lengthier (though I don't think it's ugly yet). But, yes unless measured I can't be sure which is more optimal (gut feel: looping through the files twice would be longer). BTW, ${file#$dir}_${dir#sent} should do right? Yes, rsync is for copying not moving – tpb261 Dec 11 '18 at 6:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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