How to move a file recursively based on size and keep structure

filesfindrenamescripting

I want to move files bigger than "300Mb" from one directory tree where each file is located in subfolders

Example: I have a directory structure:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Here is the expected result, a "move" of the directory tree where each file is a moved to the sub folders:

dirB/            #  normal directory
dirB/file1       #  moved from dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  moved from dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  moved from dirA/y/file3

The find /path/ -type f -size +300m but then what? and unfortunately some of the files have all sorts of characters you can find on your keyboard.

I have been looking at this thread where someone is talking about cpio but I don't know that program…

PS: have GNU Parallel installed if this could speed up things?

Best Answer

The easy way is with zsh. You can use glob qualifiers to match files according to criteria such as their type and size. The wildcard pattern **/ matches any level of subdirectories. The history modifiers h and t are easy ways of extracting the directory and the base part of a filename. Call mkdir -p to create the directories when needed.

cd dirA
for x in **/*(.Lm+300); do
  mkdir -p ../dirB/$x:h &&
    mv -- $x ../dirB/$x
done

The portable way is with find. Use -exec to invoke a shell snippet for every file.

cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
  mkdir -p "../dirB/${x%/*}"
  mv "$x" "../dirB/$x"
done' sh {} +

Parallelization is rarely useful for input/output: it lets you take advantage of multiple CPUs but the CPU is rarely a bottleneck in I/O.

Related Question