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?

  • 1
    More answers here, though they do not look as good; serverfault.com/questions/3154/… – Roel Van de Paar Jun 1 '16 at 8:43
  • 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. – Dr Beco Jul 12 '16 at 20:27

13 Answers 13

up vote 218 down vote accepted

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.)

  • 47
    Is it possible to use something similar if /home/user/skel does exist? – bradley.ayers Aug 24 '11 at 2: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 9:58
  • 7
    @bradley.ayers Bruno's answer below addresses your question – Mark Aug 20 '13 at 15:38
  • 1
    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
  • 2
    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) – bshea Jun 23 '17 at 15:45

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.

  • 3
    If I didn't get it wrong, this didn't copy hidden/dot files. – Halil Özgür Mar 16 '13 at 9:56
  • 25
    Works well for me. Note that the '.' is critical to it working. – Mark Aug 20 '13 at 15:39
  • 11
    It works, but, why ? Can't find a reference to this in the manual. – Julien Palard Jan 14 '14 at 13:37
  • 4
    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
  • 20
    @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 1 '16 at 20:39

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
  • 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
  • 3
    This really is the best answer and gets to the heart of the question.. – Stephen May 23 '14 at 16:51
  • 5
    It's setopt for zsh, in case anyone else is wondering. – Pat Dec 29 '14 at 23:18

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.

  • 2
    Correct answer. +1 – bshea Jun 23 '17 at 15:47
  • this was indeed exactly the right answer – Gaetan Feb 27 at 16:12
  • this is the BEST answer of the bunch; its the only one that solves the problem without complicating it – ZaxLofful Sep 12 at 18:25

Use rsync:

rsync -rtv source_folder/ destination_folder/

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
  • Or you could simply use cp -r /etc/skel /home/user for renaming skel to user... – David Sep 13 '13 at 12:46
  • That's right, only if /home/user does not exist yet. – Gabriel Hautclocq Oct 14 '13 at 11:52

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
  • I always used cp -r. Thanks for mentioning cp -a – Pinaki Mukherjee Jun 19 '17 at 18:40

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

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

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.

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.

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/* /etc/skel/.* /home/user
  • this would miss files like ..anything or ...anything etc. - 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 6 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 6 at 22:30
  • 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 explains it further and provides a solution. – DJCrashdummy Sep 7 at 16:23

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!

  • "a question box that pops up" — for a shell (CLI) command? – Scott Dec 15 '16 at 1:02

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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