This is a multi-line one-liner to be run in the source dir:
find -type f -printf '%s/%p\0' | # get paths with sizes together into safe zero-delimited lines
sort -zn | # do numeric sort (ascending)
cut -zd/ -f2- | #cut the sizes down
xargs -0 cp -v --parents --target-directory="../B/" # do the copy
Notes:
- do not forget to
cd path/to/source/dir
.
- replace
"../B/"
with a relative or an absolute path to the destination dir.
- the file names can contain any characters, including spaces, newlines,
$%^<>""
and other tricky stuff.
- it preserves paths, creating necessary sub-folders on the destination.
- one can omit
-v
to make cp
silent.
- the metadata is not preserved, use
cp
's --preserve=all
for that.
- this script COPIES, not moves files. The reason is being that:
- There is no
mv --parents
command and I was lazy to emulate it.
- Inside the one file system you can simply rename the whole source dir to destination, which makes files to be "moved" instantaneously. However, the move to the other file system is done trough copy+remove source sequence anyways.
Here is how I understand your dataset/create test data:
# making test dirs
mkdir test/{,A,B}
cd test/A
mkdir sub{1..4} sub1/sub{1..2}
# making test file of random sizes
find -mindepth 1 -type d -exec sh -c 'cd "$1"; x=${RANDOM}0; dd if=/dev/urandom of=${RANDOM}.${x}.bin count=${x}' - {} \;
$ tree -s .. # review
..
├── [ 0] A
│ ├── [ 0] sub1
│ │ ├── [ 89502720] 5334.174810.bin
│ │ ├── [ 0] sub1
│ │ │ └── [ 126310400] 24545.246700.bin
│ │ └── [ 0] sub2
│ │ └── [ 124303360] 17288.242780.bin
│ ├── [ 0] sub2
│ │ └── [ 149780480] 22029.292540.bin
│ ├── [ 0] sub3
│ │ └── [ 9246720] 19263.18060.bin
│ └── [ 0] sub4
│ └── [ 110320640] 31098.215470.bin
└── [ 0] B
8 directories, 6 files
Listing:
$ find -type f -printf '%s/%h/%f\0' | sort -zn | cut -zd/ -f2- | tr '\0' '\n' | xargs -l ls -lh
-rw-r--r-- 1 user group 8.9M Aug 7 14:31 ./sub3/19263.18060.bin
-rw-r--r-- 1 user group 86M Aug 7 14:30 ./sub1/5334.174810.bin
-rw-r--r-- 1 user group 106M Aug 7 14:31 ./sub4/31098.215470.bin
-rw-r--r-- 1 user group 119M Aug 7 14:30 ./sub1/sub2/17288.242780.bin
-rw-r--r-- 1 user group 121M Aug 7 14:30 ./sub1/sub1/24545.246700.bin
-rw-r--r-- 1 user group 143M Aug 7 14:31 ./sub2/22029.292540.bin
How it works:
$ find -type f -printf '%s/%p\0' | # get paths with sizes together into safe zero-delimited lines
sort -zn | # do numeric sort (ascending)
cut -zd/ -f2- | #cut the sizes down
xargs -0 cp -v --parents --target-directory="../B/" # do the copy
./sub3 -> ../B/./sub3
'./sub3/19263.18060.bin' -> '../B/./sub3/19263.18060.bin'
./sub1 -> ../B/./sub1
'./sub1/5334.174810.bin' -> '../B/./sub1/5334.174810.bin'
./sub4 -> ../B/./sub4
'./sub4/31098.215470.bin' -> '../B/./sub4/31098.215470.bin'
./sub1/sub2 -> ../B/./sub1/sub2
'./sub1/sub2/17288.242780.bin' -> '../B/./sub1/sub2/17288.242780.bin'
./sub1/sub1 -> ../B/./sub1/sub1
'./sub1/sub1/24545.246700.bin' -> '../B/./sub1/sub1/24545.246700.bin'
./sub2 -> ../B/./sub2
'./sub2/22029.292540.bin' -> '../B/./sub2/22029.292540.bin'