Dado que seus nomes de arquivos são únicos, isso funcionará, ainda que lentamente:
#!/bin/sh
src=$1
tgt=$2
# Iterate over all the filenames in the source directory.
(cd $src && find . -type f -print) | while read src_path; do
src_dir=$(dirname "$src_path")
src_base=$(basename "$src_path")
# find the file on the target with the same name.
tgt_path=$(find $tgt -name "$src_base")
# skip to next file if there's no matching filename
# in the target directory.
[ "$tgt_path" ] || continue
# create the destination directory and move the file.
mkdir -p "$tgt/$src_dir"
mv "$tgt_path" "$tgt/$src_dir"
done
Note que (a) não há muita verificação de erros acontecendo aqui, (b) vai demorar um pouco se você tiver muitos arquivos, e (c) como escrito, isso provavelmente deixará muitos diretórios vazios no alvo.
Aqui está meu teste limitado. Com um diretório de origem que parece isso:
$ find src -type f
src/b/file2.txt
src/a/file1.txt
src/c/file3.txt
E um diretório de destino com esta aparência:
$ find tgt -type f
tgt/file1.txt
tgt/file2.txt
tgt/not/the/right/place/file3.txt
Se eu tiver o script acima em um arquivo chamado reorg.sh
e executá-lo como
isso:
$ sh reorg.sh src tgt
Acabo com um diretório de destino que se parece com isso:
$ find tgt -type f
tgt/b/file2.txt
tgt/a/file1.txt
tgt/c/file3.txt