How to Copy Smallest Files First Using Shell Commands

cpfile-copyshellsize;

I have a large directory containing subdirectories and files that I wish to copy recursively.

Is there any way to tell cp that it should perform the copy operation in order of file size, so that the smallest files get copied first?

Best Answer

This does the whole job in one go - in all child directories, all in a single stream without any filename problems. It'll copy from smallest to largest every file you have. You will need to mkdir ${DESTINATION} if it doesn't already exist.

find . ! -type d -print0 |
du -b0 --files0-from=/dev/stdin |
sort -zk1,1n | 
sed -zn 's/^[^0-9]*[0-9]*[^.]*//p' |
tar --hard-dereference --null -T /dev/stdin -cf - |
    tar -C"${DESTINATION}" --same-order -xvf -

You know what, though? What this doesn't do is empty child directories. I could do some redirection over that pipeline, but it's just a race condition waiting to happen. Simplest is probably best. So just do this afterwards:

find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
    . /dev/stdin

Or, since Gilles makes a very good point in his answer to preserve directory permissions, I should try also. I think this will do it:

find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] || 
    cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin

I'd be willing to bet that's faster than mkdir anyway.

Related Question