638

How can I make cp -r copy absolutely all of the files and directories in a directory

Requirements:

  • Include hidden files and hidden directories.
  • Be one single command with an flag to include the above.
  • Not need to rely on pattern matching at all.

My ugly, but working, hack is:

cp -r /etc/skel/* /home/user
cp -r /etc/skel/.[^.]* /home/user

How can I do this all in one command without the pattern matching? What flag do I need to use?

Cfinley
  • 1,435
  • 3
  • 14
  • 20
eleven81
  • 15,376
  • 15
  • 55
  • 83
  • 1
    More answers here, though they do not look as good; http://serverfault.com/questions/3154/recursively-copying-hidden-files-linux/ – Roel Van de Paar Jun 01 '16 at 08:43
  • 2
    Please, Eleven81, consider changing the accepted answer to that given by @bruno pereira, because it avoids creating a new folder. If not, let this comment be a warning to new readers to check also the other (most voted) answer. Tx. – DrBeco Jul 12 '16 at 20:27
  • How about running `shopt -u dotglob` to include hidden files then run `cp -rfv /etc/skel /home/user` which will also show you progress in case you are copying a big directory. – Phemelo Khetho Apr 22 '20 at 02:45

18 Answers18

731

Lets say you created the new folder (or are going to create one) and want to copy the files to it after the folder is created

mkdir /home/<new_user>
cp -r /etc/skel/. /home/<new_user>

This will copy all files/folder recursively from /etc/skel in to the already existing folder created on the first line.

Bruno Pereira
  • 8,916
  • 1
  • 16
  • 17
  • 6
    If I didn't get it wrong, this didn't copy hidden/dot files. – Halil Özgür Mar 16 '13 at 09:56
  • 79
    Works well for me. Note that the '.' is critical to it working. – Mark Aug 20 '13 at 15:39
  • 17
    It works, but, why ? Can't find a reference to this in the manual. – Julien Palard Jan 14 '14 at 13:37
  • This is the best answer for what I needed and probably many others. – Kristopher Ives Apr 07 '14 at 22:04
  • 6
    I think it works because normally, this would create a new folder with the name of the last folder in the first argument. However, since that name is `.`, this behavior would require it to create an already-existing directory, so it just skips that step. – Zenexer Jun 11 '14 at 20:07
  • Considered an edit but will rather comment to give more chance for review. I think there should be a third command line saying `chown -R : /home/` to pass ownership of the files to the new user. – Pavel Šimerda Feb 11 '15 at 20:26
  • 1
    Well, I will disagree, the current answer is the right one for the question. You would need to also edit the title of the question (and the question itself) to match the suggested edit to this answer. – Bruno Pereira Feb 11 '15 at 20:55
  • Well it's never bad if the answer is better than the question. Could be in a separate note. If you don't do that, you'll end up with a non-working which may be surprising because the system tools that copy the skeleton automatically do make sure the ownership is correct. I'd even say that this is a solution to the question but it *creates* a new problem on the way that it doesn't solve. – Pavel Šimerda Feb 12 '15 at 12:13
  • 2
    Note that the answers are not only for the OP but also for anyone who finds the page via web search. – Pavel Šimerda Feb 12 '15 at 12:14
  • 4
    The reason that this works is that it's equivalent to `cp -r /etc/skel /home/`. The dot `.` is a shell equivalent name for "_This directory_", just as the double-dot `..` means "_Go up one directory_" relative to the given path. It's a relative path specifier. Try this: `ls -d /etc/skel/.` You should see that bash `eval`s this to: `/etc/skel/.` If you were to try `ls -l /home//.`, you would see files in `/home/` – TrinitronX Mar 20 '15 at 18:00
  • @BrunoPereira: Thanks! Your solution worked for me but i'm curious to know why using '.' (dot) copies the hidden file. – Technext Jan 29 '16 at 13:04
  • Hy @Technext, the explanation from TrinitronX seems to be on the spot: could not explain it better myself. – Bruno Pereira Feb 01 '16 at 13:01
  • Hmmm...i did read his comment but was then confused why * doesn't work. Seems * matches everything but dot (.) files. – Technext Feb 01 '16 at 13:26
  • 59
    @Technext The default globbing in bash does not include filenames starting with a `.`, to change that you need to use the `shopt -s dotglob` command before to be able to include those files. So with `*`, by default, you are asking to copy all files recursively from this directory that can be expanded using `*` (which does not include hidden files by default). While on the other end with `.` you are using cp to recursively copy everything from "this directory". – Bruno Pereira Feb 01 '16 at 20:39
  • @BrunoPereira: Thanks a lot for the explanation! :) Now it's all clear. :) – Technext Feb 02 '16 at 13:08
  • 3
    This should be an accepted answer – drew1kun Aug 15 '17 at 04:48
  • 1
    @JulienPalard [We finally have an answer to that!](https://unix.stackexchange.com/a/409227/67771) – iFreilicht Dec 06 '17 at 23:35
  • 1
    Note that you should use `cp -R` because `cp -r` is not well-defined by POSIX (and has a slightly different behaviour on macOS). See https://pubs.opengroup.org/onlinepubs/009695399/utilities/cp.html and https://unix.stackexchange.com/questions/18712/difference-between-cp-r-and-cp-r-copy-command – sitaktif Jun 22 '20 at 06:49
  • Great answer. I've been stumped by this many times. So, to copy from some dir into the current dir, the command is as follows. Don't be confused by the two dots: `cp -r path/to/from_dir/. .` – Gabriel Staples Jul 18 '23 at 00:31
404

Don't specify the files:

cp -r /etc/skel /home/user

(Note that /home/user must not exist already, or else it will create /home/user/skel.)

Randy Orrison
  • 7,371
  • 2
  • 28
  • 25
  • 91
    Is it possible to use something similar if `/home/user/skel` *does* exist? – bradley.ayers Aug 24 '11 at 02:10
  • @bradley.ayers I think one could copy into a temporary subdirectory then move them to the upper level (since moving in the same drive is fast). Less than ideal, but shorter than other solutions to me. – Halil Özgür Mar 16 '13 at 09:58
  • 8
    @bradley.ayers Bruno's answer below addresses your question – Mark Aug 20 '13 at 15:38
  • 4
    This solution didn't work for me. It did not copy hidden files. I'm using CentOS release 6.5. @Bruno's solution did the trick. – Technext Jan 29 '16 at 13:02
  • 4
    Under ubuntu/debian this places the directory 'skel' inside target directory and not the recursed files inside skel. Use `-T` (no target) per below for proper use. (`-rT` for recursive) – B. Shea Jun 23 '17 at 15:45
  • 1
    This does not copy hidden (dot) files like '.profile' or '.bashrc' – drew1kun Aug 15 '17 at 04:49
  • 1
    If `/home/user` does exist, then this will copy the contents of `/etc/skel` without making `/home/user/skel`: `find /etc/skel -type f -exec cp {} /home/user \;` – Ralph Bolton Sep 14 '17 at 10:39
  • 1
    **Beware** that this does not preserve file-attributes by default. So make sure to add your mix of timestamps/xattr/etc. via the -p/--preserve flag! (compare man page) – isync Jan 07 '18 at 19:34
  • 20
    Answering a 7.5 year old question, you can run `cp -r /etc/skel/. /home/user` to avoid creating the subdirectory (note the `/.` following etc/skel). – carpeliam Mar 19 '19 at 20:00
256

The correct means of doing this is to use the -T (--no-target-directory) option, and recursively copy the folders (without trailing slashes, asterisks, etc.), i.e.:

cp -rT /etc/skel /home/user

This will copy the contents of /etc/skel to /home/user (including hidden files), creating the folder /home/user if it does not exist; however the -T option prevents the contents of /etc/skel from being copied to a new folder /home/user/skel should the folder /home/user exist.

TechnocratiK
  • 2,661
  • 1
  • 9
  • 2
81

bash itself has a good solution, it has a shell option, You can cp, mv and so on.:

shopt -s dotglob # for considering dot files (turn on dot files)

and

shopt -u dotglob # for don't considering dot files (turn off dot files)

Above solution is standard of bash

NOTE:

shopt # without argument show status of all shell options
-u # abbrivation of unset 
-s # abbrivation of set
PersianGulf
  • 953
  • 8
  • 10
  • 2
    That's usefull when you want to copy just content without creating new directory inside destination. Especially when destination dir is mount point. – kaszynek Nov 11 '13 at 12:27
  • 10
    It's `setopt` for zsh, in case anyone else is wondering. – Pat Dec 29 '14 at 23:18
36

Use rsync:

rsync -rtv source_folder/ destination_folder/

user1084282
  • 471
  • 4
  • 2
8

rsync is good, but another choice:

cp -a src/ dst/

From the main help:

   -a, --archive
          same as -dR --preserve=all

   -d     same as --no-dereference --preserve=links

   -R, -r, --recursive
          copy directories recursively
Excellll
  • 12,627
  • 11
  • 51
  • 78
Wink Saville
  • 97
  • 1
  • 1
  • This answer is incorrect in terms of the original question asked (include hidden files): both `cp -r` as well as `cp -a` copy hidden files when cp ... src dst or cp ... src/ dst/ is used. It may be that this changed overtime. – Roel Van de Paar Sep 08 '20 at 03:52
  • works like a charm. – Evan Hu Nov 19 '22 at 07:19
6

The simplest way is:

cp -r /etc/skel/{.,}* /home/user

The expression {.,}* includes all files and directories (also starting with a dot).

If you don't want use above expression, then you can use the cp property, which is the ability to specify multiple sources for one target folder:

cp -r /etc/skel/* /home/user
simhumileco
  • 667
  • 7
  • 14
  • 2
    this would miss files like `..anything` or `...anything` etc. - https://stackoverflow.com/a/31438355/2351568 contains the correct regex for this problem. **||** but anyway using `shopt -s dotglob` is still the better solution! – DJCrashdummy Sep 06 '18 at 17:53
  • @DJCrashdummy unfortunately, I do not understand why you wrote your attention. After all, my solution takes into account the cases you write about. Regards – simhumileco Sep 06 '18 at 22:30
  • 2
    sorry wrong text! - the problem with your answer is, that it will also consider `.` and `..` (which is equivalent to the current and its containing folder). **||** but still the [answer in the link](https://stackoverflow.com/a/31438355/2351568) explains it further and provides a solution. – DJCrashdummy Sep 07 '18 at 16:23
  • This answer is very wrong as it actually recuses UP the file tree! – Gabriel Devenyi Mar 16 '23 at 14:32
5

You could use rsync.

rsync -aP ./from/dir/ /some/other/directory/

You can even copy over ssh

rsync -aP ./from/dir/ username@remotehost:/some/other/directory/

There are various flags you can use: -a, --archive # archive (-rlptgoD)

-r, --recursive
-l, --links      # copy symlinks as links
-p, --perms      # preserve permissions
-t, --times      # preserve times
-g, --group      # preserve group
-o, --owner      # preserve owner
-D               # --devices --specials

--delete         # Delete extra files

You may want to add the -P option to your command.

--partial        # By default, rsync will delete any partially transferred file if the transfer is interrupted. In some circumstances it is more desirable to keep partially transferred files. Using the --partial option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster.

-P               # The -P option is equivalent to --partial --progress.   Its  purpose  is to make it much easier to specify these two options for a long transfer that may be interrupted.

Rsync man page

RoshP
  • 51
  • 1
  • 2
5

If your source and target directory have the same name, even if target directory exists, you can simply type:

cp -R /etc/skel /home/

This will copy the /etc/skel directory into /home/, including hidden files and directories.

Eventually, you can copy the directory and rename it in a single line :

cp -R /etc/skel /home/ && mv /home/skel /home/user
4

I came here having Googled for a solution to the same problem, then I realized that it's easy to do with find. The advantage it doesn't depend on the shell, or special utilities that may not be installed.

find /etc/skel/ -mindepth 1 -exec cp -r {} /home/username/ \;

I tried the trick with trailing slash, but that didn't work for me.

Mureinik
  • 3,974
  • 11
  • 28
  • 32
Linus
  • 41
  • 1
  • This also lets you exclude some files/directories with exclusion filters (e.g. `! -name 'dontcopythis'`) which might be handy. – FK82 Oct 08 '21 at 15:13
3

Note that there is a command-line trick (works in, at least, sh, bash, and ksh): Just suffix the from directory with a slash. This will pour the contents of the from directory into the to directory (ironically, I had first learned about this trick when using rsync).

Example:

/tmp$ mkdir test_dir1
/tmp$ cd test_dir1/
/tmp/test_dir1$ touch aa
/tmp/test_dir1$ touch .bb
/tmp/test_dir1$ cd ..
/tmp$ mkdir test_dir2

/tmp$ cp -r test_dir1/* test_dir2
/tmp$ ls -1a test_dir2
.
..
aa

/tmp$ cp -r test_dir1/ test_dir2
/tmp$ ls -1a test_dir2
.
..
.bb
aa
Dustin Oprea
  • 341
  • 1
  • 3
  • 11
2

My solution for this problem when I have to copy all the files (including . files) to a target directory retaining the permissions is: (overwrite if already exists)

yes | cp -rvp /source/directory /destination/directory/

yes is for automatically overwriting destination files, r recursive, v verbose, p retain permissions.

Notice that the source path is not ending with a / (so all the files/directory and . files are copied)

Destination directory ends with / as we are placing contents of the source folder to destination as a whole.

2

You can copy the content of a folder /source to another existing folder /dest, including hidden files, with the command:

$ cp -a /source/. /dest/

The -a option is an improved recursive option, that preserve all file attributes, and also preserve symlinks.

The . at end of the source path is a specific cp syntax that allowes to copy all files and folders, including hidden ones.

casimir
  • 29
  • 1
  • Avoid posting answers to old questions that already have well received answers unless you have something substantial and new to add. – Toto Sep 16 '22 at 08:22
  • Agree with @Toto - Your answer is the same as that of [@BrunoPereira's answer](https://superuser.com/a/367303/1210833) which was posted 11 years ago and already has nearly 700 upvotes. I know there are a lot of answers here to read through before posting yours, but please do it. There's just no sense in adding *yet answer* to the long list (currently 20) unless you truly have something new and useful to add. It just makes it even more difficult for the *next* user to find the existing answer. Thanks! – NotTheDr01ds Nov 24 '22 at 02:01
1

I have seen that cp does not always copy hidden files and if you would like an command that seems to work across all linux/unix dialects you should try using:

cd /etc/skel
find | cpio -pdumv /home/user
0

I few years late but the solution is rather simple, really.

cp -r /etc/skel/. /home/user/

The slash (/) after "user" does make a difference.

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 09 '23 at 19:15
-1

ignore error

cp -r asdf/* qwer/
cp -r asdf/.[^.]* qwer/ 2>/dev/null | true
seunggabi
  • 99
  • 1
  • Avoid posting answers to old questions that already have well received answers unless you have something substantial and new to add. – Toto Jan 04 '23 at 17:19
-2

To copy files, directories and hidden files from a directory to existing/new directory:

cp -a /etc/skel /home/user

Copy to current directory:

cp -a /etc/skel/. .
-3

As of at least K3b 2.0.3, there is a question box that pops up when the directory is added to the project, that ask if you want to include hidden files ... there is also a question that pops up to ask about including links. Nice stuff!