Bash script to copy a directory from multiple subdirectories with directory structure

New to shell script, have to copy the class files from different subdirectories to another destination directory My directory structure is

Module
    |-- submodule
    |         |--main
    |         |--test
    |         |--target
    |               |__classes
    |               |__src  
    |
    |
    |-- subdirectory
              |--maintest
              |--target
                    |__ classes
                    |__ src

I have to copy all the files from target/classes directory to destination directory "POM" and expecting the directory structure as below

 POM
    |-- submodule
    |         |__ target
    |               |__classes
    |
    |-- subdirectory
              |_target
                    |__ classes

tried using the below command

for dest in POM/; do cp -r modules/*/target/classes $dest; done

But it copied only the submodule2 directories.

Note: we are restricted to use the rsync command.


Solution 1:

Given this file tree:

 tree /tmp/Module
/tmp/Module
├── submodule1
│   └── target
│       └── classes
│           ├── class_1
│           ├── class_2
│           ├── class_3
│           ├── class_4
│           └── class_5
└── submodule2
    └── target
        └── classes
            ├── class_1
            ├── class_2
            ├── class_3
            ├── class_4
            └── class_5

6 directories, 10 files

Just use cp -R [source path] [target path] (ie, no shell loop needed and no glob):

% cp -vR /tmp/Module /tmp/POM
/tmp/Module -> /tmp/POM
/tmp/Module/submodule2 -> /tmp/POM/submodule2
/tmp/Module/submodule2/target -> /tmp/POM/submodule2/target
/tmp/Module/submodule2/target/classes -> /tmp/POM/submodule2/target/classes
/tmp/Module/submodule2/target/classes/class_4 -> /tmp/POM/submodule2/target/classes/class_4
/tmp/Module/submodule2/target/classes/class_3 -> /tmp/POM/submodule2/target/classes/class_3
/tmp/Module/submodule2/target/classes/class_2 -> /tmp/POM/submodule2/target/classes/class_2
/tmp/Module/submodule2/target/classes/class_5 -> /tmp/POM/submodule2/target/classes/class_5
/tmp/Module/submodule2/target/classes/class_1 -> /tmp/POM/submodule2/target/classes/class_1
/tmp/Module/submodule1 -> /tmp/POM/submodule1
/tmp/Module/submodule1/target -> /tmp/POM/submodule1/target
/tmp/Module/submodule1/target/classes -> /tmp/POM/submodule1/target/classes
/tmp/Module/submodule1/target/classes/class_4 -> /tmp/POM/submodule1/target/classes/class_4
/tmp/Module/submodule1/target/classes/class_3 -> /tmp/POM/submodule1/target/classes/class_3
/tmp/Module/submodule1/target/classes/class_2 -> /tmp/POM/submodule1/target/classes/class_2
/tmp/Module/submodule1/target/classes/class_5 -> /tmp/POM/submodule1/target/classes/class_5
/tmp/Module/submodule1/target/classes/class_1 -> /tmp/POM/submodule1/target/classes/class_1

Result:

% tree /tmp/POM
/tmp/POM
├── submodule1
│   └── target
│       └── classes
│           ├── class_1
│           ├── class_2
│           ├── class_3
│           ├── class_4
│           └── class_5
└── submodule2
    └── target
        └── classes
            ├── class_1
            ├── class_2
            ├── class_3
            ├── class_4
            └── class_5

6 directories, 10 files

If you actually want a Bash script to do this (for instance if you want to process some of these files), you would do something along these lines:

#!/bin/bash

cd /tmp || exit
fc=0; dc=0
for fn in /tmp/Module/**/*; do
    if [ -d "$fn" ]; then
        # react to directories here
        printf "directory %s ->t %s\n" "$fn" "${fn/Module/POM}"
        mkdir -p "${fn/Module/POM}"
        (( dc++ ))
    else
        # everything else returned by **/* here
        printf "file %s -> %s\n" "$fn" "${fn/Module/POM}"
        cp "$fn" "${fn/Module/POM}"
        (( fc++ ))
    fi  
done    
printf "\n%'d directories, %'d files" "$dc" "$fc"

Prints:

directory /tmp/Module/submodule1 ->t /tmp/POM/submodule1
directory /tmp/Module/submodule1/target ->t /tmp/POM/submodule1/target
directory /tmp/Module/submodule1/target/classes ->t /tmp/POM/submodule1/target/classes
file /tmp/Module/submodule1/target/classes/class_1 -> /tmp/POM/submodule1/target/classes/class_1
file /tmp/Module/submodule1/target/classes/class_2 -> /tmp/POM/submodule1/target/classes/class_2
file /tmp/Module/submodule1/target/classes/class_3 -> /tmp/POM/submodule1/target/classes/class_3
file /tmp/Module/submodule1/target/classes/class_4 -> /tmp/POM/submodule1/target/classes/class_4
file /tmp/Module/submodule1/target/classes/class_5 -> /tmp/POM/submodule1/target/classes/class_5
directory /tmp/Module/submodule2 ->t /tmp/POM/submodule2
directory /tmp/Module/submodule2/target ->t /tmp/POM/submodule2/target
directory /tmp/Module/submodule2/target/classes ->t /tmp/POM/submodule2/target/classes
file /tmp/Module/submodule2/target/classes/class_1 -> /tmp/POM/submodule2/target/classes/class_1
file /tmp/Module/submodule2/target/classes/class_2 -> /tmp/POM/submodule2/target/classes/class_2
file /tmp/Module/submodule2/target/classes/class_3 -> /tmp/POM/submodule2/target/classes/class_3
file /tmp/Module/submodule2/target/classes/class_4 -> /tmp/POM/submodule2/target/classes/class_4
file /tmp/Module/submodule2/target/classes/class_5 -> /tmp/POM/submodule2/target/classes/class_5

6 directories, 10 files

You can also just use rsync. A basic example would be:

$ rsync -vr /tmp/Module /tmp/POM
# -r for recursive; all targets created and all files copied.