The GNU implementation of du can give you a report of:
- cumulative disk usage (default)
- cumulative size with
--apparent-size
- cumulative number of files (of any type) with
--inode
For directories and their contents (unfortunately, it can't include all three in one report).
You can also tell it not to deduplicate hard links with -l / --count-links.
It's one of the rare ones whose output you can post-process reliably as it's got a -0 / --null option to output NUL-delimited records.
So if you're on a GNU system, you could do:
xargs -r0a <(
du --inode --null --count-links | # count inodes
tac -s '' | # reverse the output so parents are shown before children
perl -0lnse '
if (
m{^(\d+)\t(.*)}s &&
$1 < $max &&
rindex($2, "$last_moved/", 0) < 0 # not a subdirectory of the last moved
) {
print($last_moved = $2);
}' -- -max=10
) echo mv -it /path/to/destination --
Which would move the directories that contain (recursively) fewer than 10 files (of any type including directory, and including the directory itself).
Replace --inode with --apparent-size --block-size=1 (or -b for short) to consider the cumulative size instead of number of files. Same without --apparent-size for disk usage (you'll want to update -max accordingly).
Remove the echo if happy with the result to actually do it.
All of -r, -0, -a, --inode, --apparent-size, -l, --count-links, tac, -b, --block-size, -t are non-standard GNU extensions few of which have been added to other implementations of those standard utilities, so don't expect that to work outside GNU systems unless you've installed GNU coreutils and findutils there. Since you've used the linux tag though, there's a fair chance you are on GNU system.
To consider both number of files and cumulative size, you could use GNU find which has a -printf predicate which can report file type, and size and do the sums by hand:
xargs -r0a <(
find . -depth -printf '%y %s %p\0' | perl -0lsne '
if (m{^(\S+) (\d+) ((.*)/.*)}s) {
my ($type, $size, $file, $parent) = ($1, $2, $3, $4);
$count{$parent} += ++$count{$file};
$size{$parent} += $size{$file} += $size;
unshift @dirs, $file if $type eq "d";
}
END {
for $dir (@dirs) {
if (
$size{$dir} < $max_size &&
$count{$dir} < $max_count &&
rindex($dir, "$last_moved/", 0) < 0
) {
print $last_moved = $dir;
}
}
}' -- -max_count=10 -max_size="$(( 5 * 1024 * 1024 ))"
) echo mv -it /path/to/destination --
For the disk usage instead of apparent size, replace %s with %b which you'll have to multiply by 512 (replace $2 with $2 * 512 above) to get the disk usage in bytes.