3

Let's say I have as follows :

Folder A
    C1
        file a
    A2

Folder B
     C1
     B2
         file b
     B3

What I want is to merge these two folders, which would give me :

Folder C
    C1
    A2
    B2
    B3

Notice I didn't write file a and file b. I only want to merge the architecture. Each repository contains different files and I don't want them to be added to the merged directory. As a consequence, mv Folder\ A/* Folder\ B is not adequate.

Do you guys see a way to do so ?

  • so you basically want to copy the directories but not the files in the directories? – strugee Sep 5 '13 at 6:52
  • That's exactly my need. – fxm Sep 5 '13 at 6:53
  • all right, here's my lazy answer: mkdir dir3 && cp -r dir1/* dir3/ && cp -r dir2/* dir3/, then use find to go through and find any regular files and delete them. – strugee Sep 5 '13 at 6:56
  • 2
    @strugee; Expensive. Use cp -rl to hardlink, then it's cheaper. – M.E.L. Sep 5 '13 at 8:00
7

Well, you could have find exec mkdir.

cd /A/
find -type d -exec mkdir -p /C/{} \;

Or if the structure is flat as shown in your example, without find

cd /A/
for dir in */
do
    mkdir -p /C/"$dir"
done

and in both cases the same again for cd /B/.

  • I tried your first solution (structure is not flat), but I'm affraid I can't find the folder C. Where is it supposed to go ? – fxm Sep 5 '13 at 8:50
  • @fxm: He's just abbreviating your folder names. Where he says A, he means the same thing you named as Folder A. So, C is Folder C. File names with spaces in them require careful attention to quoting, so it's simpler to give a correct example this way. – Warren Young Sep 5 '13 at 9:12
  • Also note it needs either absolute paths or paths relative to /A/ or /B/, e.g. ../C/ instead of C/. I assumed A B C was an example and you know how to specify the location of the real directories. – frostschutz Sep 5 '13 at 9:15
  • I realize it, but changing /C/ by ~/newFolder/ doesn't seems to create the afroementionned folder in my home – fxm Sep 5 '13 at 9:21
  • Oh, sorry, my bad. Use \; instead of +. – frostschutz Sep 5 '13 at 9:29
2

If you just want to create the same directory structure, you can call find to traverse each existing directory tree and call mkdir with the right argument on each subdirectory. Call mkdir -p to silently skip directories that already exist.

cd 'Folder A'
find . -type d -exec mkdir -p '/path/to/Folder C/{} '\;
cd 'Folder B'
find . -type d -exec mkdir -p '/path/to/Folder C/{} '\;

In zsh, assuming that Folder A, Folder B and Folder C are subdirectories of the same directory:

mkdir -p Folder\ [AB]/**/*(/e\''REPLY=Folder\ C/${REPLY#*/}'\')

If you want to reproduce the directory hierarchy with file permissions, you can call rsync, and give it a filter that only includes the directories and not the regular files. Make sure to include a / at the end of the source directories so that their content is copied directly under /path/to/Folder C without creating /path/to/Folder C/path/to/Folder A and so on.

rsync -a --include='*/' --exclude='*' '/path/to/Folder A/' '/path/to/Folder B/' '/path/to/Folder C'
0

Here's how I would do it:

$ (find "Folder A"/* -type d ; find "Folder B"/* -type d) | \
           sed 's#[^/]\+/##' | xargs -I{} mkdir -p "Folder C"/{}

Details

This will generate the list of sub-directories under "Folder A" and Folder B", that list will look like this:

Folder A/A2
Folder A/C1
Folder B/B2
Folder B/B3
Folder B/C1

Piping that output through this sed command will remove the "Folder .." bit:

sed 's#[^/]\+/##'

Resulting in this:

A2
C1
B2
B3
C1

NOTE: The above sed is looking from the left side, finding everything that is not a slash, up to the first slash, these characters are then substituted with nothing, essentially deleting them.

At this point you just need to mkdir under the "Folder C" directory, so we'll use xargs to do this repetitive task:

xargs -I{} mkdir -p "Folder C"/{}

This says to take each argument in as {} and substitute it into the following command ever where there's a corresponding {}.

Example

Sample data:

$ tree Folder\ {A,B,C}
Folder A
|-- A2
`-- C1
    `-- filea
Folder B
|-- B2
|   `-- fileb
|-- B3
`-- C1
Folder C

NOTE: See "Folder C" is empty to start.

Now we run our command:

$ (find "Folder A"/* -type d ; find "Folder B"/* -type d) | \
           sed 's#[^/]\+/##' | xargs -I{} mkdir -p "Folder C"/{}

And we're left with the following:

$ tree Folder\ C
Folder C
|-- A2
|-- B2
|-- B3
`-- C1
  • How about find A/ B/ -type d -print0 | sed -z ... | xargs -0 ...? – frostschutz Sep 5 '13 at 17:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.