143

I want to create a clone of the structure of our multi-terabyte file server. I know that cp --parents can move a file and it's parent structure, but is there any way to copy the directory structure intact?

I want to copy to a linux system and our file server is CIFS mounted there.

Gaël Barbin
  • 3,769
  • 3
  • 25
  • 52
r00fus
  • 2,524
  • 2
  • 16
  • 16

18 Answers18

227

You could do something like:

find . -type d > dirs.txt

to create the list of directories, then

xargs mkdir -p < dirs.txt

to create the directories on the destination.

Vitaly Isaev
  • 5,392
  • 6
  • 45
  • 64
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 15
    This solutions won't work if you have spaces in your directory names. – Jealie Mar 11 '15 at 20:35
  • 47
    @Jealie Change the commands to `find . -type d -print0 >dirs.txt` and `xargs -0 mkdir -p – user1207177 Apr 03 '15 at 01:37
  • 6
    `xargs` can exceed the maximum command length of the system when you start dealing with orders of hundreds or thousands, so use this with caution. (Find the command length limit with `getconf ARG_MAX`.) With a lot of directories, you may have to write a script to loop through the output instead. – palswim Oct 13 '15 at 21:26
  • Note that the order of `-type d` and `-print0` is important! – Simon Oct 27 '15 at 19:37
  • this is a nice little find. thank you greg. thank you internet. – zach Jul 28 '16 at 02:46
  • 3
    And what about permissions & attributes will it be retained ?? – Ashish Karpe Aug 17 '16 at 07:14
  • 1
    @AshishKarpe and all the other people who voted up this answer: **permissions and attributes are NOT retained**... because you are doing a naive `mkdir -p ${x}` where x is each directory in the list. [Use rynsc to preserve the permissions and attributes](https://stackoverflow.com/a/9242883/52074). – Trevor Boyd Smith Jun 01 '17 at 20:13
  • 4
    @TrevorBoydSmith: Thanks for your comment. The original question didn't mention anything about needing to preserve permissions, ownership, or attributes. Doing so would require a different solution, as you mention, but the above is sufficient to answer the question as posed. – Greg Hewgill Jun 01 '17 at 20:16
  • @GregHewgill you are correct that your answer fulfills all the requirements in the given question. However, in practice, the many times I have "needed" to copy a directory structure... I have ALSO needed the same permissions/attributes that is why I left a link to the `rsync` solution. – Trevor Boyd Smith Jun 01 '17 at 20:20
  • 1
    I do prefer the solutions using rsync `rsync -a --include '*/' --exclude '*' "$source" "$target"` – Sylvain Mar 30 '18 at 09:17
  • Thanks @Sylvain looks like this will work while preserving permissions and hardlinks (-H) – sehe Jan 21 '19 at 15:13
101
cd /path/to/directories &&
find . -type d -exec mkdir -p -- /path/to/backup/{} \;
amphetamachine
  • 27,620
  • 12
  • 60
  • 72
  • 4
    Best answer from me with find. Else you can try `rsync` solution from Chen Levy answer in [this SO question](http://stackoverflow.com/questions/11946465/copy-a-directory-structure-with-file-names-without-content) – Mat M May 14 '14 at 13:14
  • 3
    What does the -- mkdir's option? – Bruce_Warrior Aug 08 '16 at 08:58
  • 12
    `--` is a standard GNU utility option terminator. It means "hey mkdir, any argument after this, it's not a flag, so treat it as a file argument, even if it starts with a '-' character." – amphetamachine Aug 09 '16 at 16:35
  • 5
    this answer also **does not retain the directory permissions and attributes**. [Use rynsc to preserve the permissions and attributes](https://stackoverflow.com/a/9242883/52074) – Trevor Boyd Smith Jun 01 '17 at 20:13
61

Here is a simple solution using rsync:

rsync -av -f"+ */" -f"- *" "$source" "$target"
  • one line
  • no problems with spaces
  • preserve permissions

I found this solution there

Gildas
  • 998
  • 10
  • 16
  • 20
    same but more readable `rsync -a --include '*/' --exclude '*' "$source" "$target"` – Sylvain Mar 30 '18 at 09:16
  • 3
    Problem with this solution is: my folders contain thousands of files and rsync takes ages just to sync a dozen of folders. – Christopher K. Jul 24 '18 at 19:11
  • Very nice! I used it with recursively with -r. In my experience rsync is fast as long it does not work on network file systems. In that case better use it's integrated ssh. – Hauke Jul 19 '23 at 14:49
13

1 line solution:

find . -type d -exec mkdir -p /path/to/copy/directory/tree/{} \;
Igor
  • 1,589
  • 15
  • 15
  • 2
    This works fine and works smartly. One wrinkle ylu must be in the `$source` directory to ensure your new tree is relative to the `$target` directory. But that's not one-line any more. Use: `pushd $source; find . -type d -exec mkdir -p "$target"/{} \; popd` – will Mar 27 '22 at 12:50
10

I dunno if you are looking for a solution on Linux. If so, you can try this:

$ mkdir destdir
$ cd sourcedir
$ find . -type d | cpio -pdvm destdir
sudo make install
  • 5,629
  • 3
  • 36
  • 48
zerodin
  • 857
  • 5
  • 9
8

This copy the directories and files attributes, but not the files data:

cp -R --attributes-only SOURCE DEST

Then you can delete the files attributes if you are not interested in them:

find DEST -type f -exec rm {} \;
toliveira
  • 1,533
  • 16
  • 27
  • 1
    Would be exellent one, but you forgot to mention saving ownership, timestamp and permissions. So it produced a mess in Win7/cygwin - NULL_SID user, wrong permissions order, cannot edit permissions, etc and cannot access produced filestructure. – WebComer Feb 23 '18 at 01:37
  • 3
    I should think the blame lies squarely on whoever tries to use Windows for real work. – tripleee Feb 23 '19 at 09:10
  • 1
    cp -R --attributes-only --preserve=all --parents -v SOURCE DEST – Gábor May 07 '20 at 15:08
3

This works:

find ./<SOURCE_DIR>/ -type d | sed 's/\.\/<SOURCE_DIR>//g' | xargs -I {} mkdir -p <DEST_DIR>"/{}"

Just replace SOURCE_DIR and DEST_DIR.

user1133275
  • 2,642
  • 27
  • 31
mijhael3000
  • 113
  • 1
  • 7
2

The following solution worked well for me in various environments:

sourceDir="some/directory"
targetDir="any/other/directory"

find "$sourceDir" -type d | sed -e "s?$sourceDir?$targetDir?" | xargs mkdir -p
yaccob
  • 1,230
  • 13
  • 16
2

This solves even the problem with whitespaces:

In the original/source dir:

find . -type d -exec echo "'{}'" \; > dirs2.txt

then recreate it in the newly created dir:

mkdir -p <../<SOURCEDIR>/dirs2.txt
Thim
  • 21
  • 1
1

Substitute target_dir and source_dir with the appropriate values:

cd target_dir && (cd source_dir; find . -type d ! -name .) | xargs -i mkdir -p "{}"

Tested on OSX+Ubuntu.

Tony
  • 5,972
  • 2
  • 39
  • 58
luissquall
  • 1,740
  • 19
  • 14
1

Another tool that can do this: mtree

It first appeared on bsd systems, there are ports for linux too. In Ubuntu it is in package 'mtree-netbsd' or 'freebsd-utils'.

# 1: cd to your source dir
cd my_source_dir

# 2: create a specfile. Place the spec outside of the sourcedir and destdir
mtree -c > /tmp/myspec.txt

# 3: cd to the destdir
cd my_dest_dir

# 4: now create only the dir structure from the specfile
# -u  is for creating only dirs, it does not follow links
mtree -f /tmp/myspec.txt -u

If you later deleted some dirs in the destdir call the command form step 4 again, dir-structure will be restored.

mtree can do a lot more. follow links, create/delete specific files/dirs, delete or not delete files that are in the destdir...

Sean Loony
  • 111
  • 3
0

If you can get access from a Windows machine, you can use xcopy with /T and /E to copy just the folder structure (the /E includes empty folders)

http://ss64.com/nt/xcopy.html

[EDIT!]

This one uses rsync to recreate the directory structure but without the files. http://psung.blogspot.com/2008/05/copying-directory-trees-with-rsync.html

Might actually be better :)

dotalchemy
  • 2,459
  • 19
  • 24
  • 1
    Unfortunately, our CIFS-serving fileserver isn't running windows, so no can do on win commands. – r00fus Nov 08 '10 at 23:04
  • Thank you, the rsync method worked perfectly fine for me. It's compatible with spaces in directory names as well. – Glutanimate Dec 07 '12 at 00:40
0

A python script from Sergiy Kolodyazhnyy posted on Copy only folders not files?:

#!/usr/bin/env python
import os,sys
dirs=[ r for r,s,f in os.walk(".") if r != "."]
for i in dirs:
    os.makedirs(os.path.join(sys.argv[1],i)) 

or from the shell:

python -c 'import os,sys;dirs=[ r for r,s,f in os.walk(".") if r != "."];[os.makedirs(os.path.join(sys.argv[1],i)) for i in dirs]' ~/new_destination

FYI:

Franck Dernoncourt
  • 77,520
  • 72
  • 342
  • 501
0

Another approach is use the tree which is pretty handy and navigating directory trees based on its strong options. There are options for directory only, exclude empty directories, exclude names with pattern, include only names with pattern, etc. Check out man tree

Advantage: you can edit or review the list, or if you do a lot of scripting and create a batch of empty directories frequently

Approach: create a list of directories using tree, use that list as an arguments input to mkdir

tree -dfi --noreport > some_dir_file.txt

-dfi lists only directories, prints full path for each name, makes tree not print the indentation lines,

--noreport Omits printing of the file and directory report at the end of the tree listing, just to make the output file not contain any fluff

Then go to the destination where you want the empty directories and execute

xargs mkdir < some_dir_file.txt
brother-bilo
  • 490
  • 4
  • 11
0
find source/ -type f  | rsync -a --exclude-from - source/ target/

Copy dir only with associated permission and ownership

Tiger peng
  • 647
  • 6
  • 10
0

Simple way:

for i in `find . -type d`; do mkdir /home/exemplo/$i; done
Obsidian
  • 3,719
  • 8
  • 17
  • 30
0
cd oldlocation
find . -type d -print0 | xargs -0 -I{} mkdir -p newlocation/{}

You can also create top directories only:

cd oldlocation
find . -maxdepth 1 -type d -print0 | xargs -0 -I{} mkdir -p newlocation/{}
P. D
  • 1
  • 2
  • This solution works perfectly on LinuxMint 20.2, unlike the answer validated 10 years ago. Thank you! –  Nov 08 '21 at 10:22
-1

Here is a solution in php that:

  • copies the directories (not recursively, only one level)
  • preserves permissions
  • unlike the rsync solution, is fast even with directories containing thousands of files as it does not even go into the folders
  • has no problems with spaces
  • should be easy to read and adjust

Create a file like syncDirs.php with this content:

<?php
foreach (new DirectoryIterator($argv[1]) as $f) {
    if($f->isDot() || !$f->isDir()) continue;
        mkdir($argv[2].'/'.$f->getFilename(), $f->getPerms());
        chown($argv[2].'/'.$f->getFilename(), $f->getOwner());
        chgrp($argv[2].'/'.$f->getFilename(), $f->getGroup());
}

Run it as user that has enough rights:

sudo php syncDirs.php /var/source /var/destination

Christopher K.
  • 1,015
  • 12
  • 18
  • 1
    You don't have to like PHP and you don't have to use it. But the OP did not specify whether he wants a solution in any specific language and, like it or not, PHP is installed anyways on lots of Linux systems as 80% of the web uses PHP ( https://w3techs.com/technologies/details/pl-php/all/all ). – Christopher K. Aug 21 '19 at 08:58