How to copy with cp to include hidden files and hidden directories and their contents?

423

127

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?

eleven81

Posted 2009-10-27T19:46:06.483

Reputation: 12 423

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 – 2016-06-01T08:43:54.620

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 – 2016-07-12T20:27:10.037

Answers

281

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

Posted 2009-10-27T19:46:06.483

Reputation: 5 749

1This 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 – 2016-01-29T13:02:47.303

2Under 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 – 2017-06-23T15:45:58.783

This does not copy hidden (dot) files like '.profile' or '.bashrc' – Drew – 2017-08-15T04:49:05.410

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 – 2017-09-14T10:39:02.093

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 – 2018-01-07T19:34:57.133

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 – 2019-03-19T20:00:44.600

66Is it possible to use something similar if /home/user/skel does exist? – bradley.ayers – 2011-08-24T02:10:05.157

@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 – 2013-03-16T09:58:42.380

8@bradley.ayers Bruno's answer below addresses your question – Mark – 2013-08-20T15:38:43.497

492

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

Posted 2009-10-27T19:46:06.483

Reputation: 6 450

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 <new_user>:<new_user> /home/<new_user> to pass ownership of the files to the new user. – Pavel Šimerda – 2015-02-11T20:26:07.067

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 – 2015-02-11T20:55:33.897

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 – 2015-02-12T12:13:12.637

Note that the answers are not only for the OP but also for anyone who finds the page via web search. – Pavel Šimerda – 2015-02-12T12:14:19.617

2The reason that this works is that it's equivalent to cp -r /etc/skel /home/<new_user>. 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 evals this to: /etc/skel/. If you were to try ls -l /home/<myuser>/., you would see files in /home/<myuser> – TrinitronX – 2015-03-20T18:00:16.680

@BrunoPereira: Thanks! Your solution worked for me but i'm curious to know why using '.' (dot) copies the hidden file. – Technext – 2016-01-29T13:04:09.477

Hy @Technext, the explanation from TrinitronX seems to be on the spot: could not explain it better myself. – Bruno Pereira – 2016-02-01T13:01:39.930

Hmmm...i did read his comment but was then confused why * doesn't work. Seems * matches everything but dot (.) files. – Technext – 2016-02-01T13:26:08.423

29@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 – 2016-02-01T20:39:00.643

@BrunoPereira: Thanks a lot for the explanation! :) Now it's all clear. :) – Technext – 2016-02-02T13:08:36.837

1This should be an accepted answer – Drew – 2017-08-15T04:48:07.563

1

@JulienPalard We finally have an answer to that!

– iFreilicht – 2017-12-06T23:35:09.403

6If I didn't get it wrong, this didn't copy hidden/dot files. – Halil Özgür – 2013-03-16T09:56:37.577

38Works well for me. Note that the '.' is critical to it working. – Mark – 2013-08-20T15:39:54.707

13It works, but, why ? Can't find a reference to this in the manual. – Julien Palard – 2014-01-14T13:37:47.920

This is the best answer for what I needed and probably many others. – Kristopher Ives – 2014-04-07T22:04:43.003

5I 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 – 2014-06-11T20:07:35.557

95

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

Posted 2009-10-27T19:46:06.483

Reputation: 1 051

4Correct answer. +1 – bshea – 2017-06-23T15:47:44.680

this was indeed exactly the right answer – Gaetan – 2018-02-27T16:12:49.320

this is the BEST answer of the bunch; its the only one that solves the problem without complicating it – ZaxLofful – 2018-09-12T18:25:28.940

exactly works to copy as expected – Chetabahana – 2019-03-31T11:01:52.263

Love it when you use the correct cmd flag for the one case. – Tran Triet – 2019-09-11T03:59:34.060

68

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

Posted 2009-10-27T19:46:06.483

Reputation: 823

7It's setopt for zsh, in case anyone else is wondering. – Pat – 2014-12-29T23:18:23.253

2That's usefull when you want to copy just content without creating new directory inside destination. Especially when destination dir is mount point. – kaszynek – 2013-11-11T12:27:03.113

3This really is the best answer and gets to the heart of the question.. – Stephen – 2014-05-23T16:51:55.900

29

Use rsync:

rsync -rtv source_folder/ destination_folder/

user1084282

Posted 2009-10-27T19:46:06.483

Reputation: 401

Best option for me, although I use --progress to have more feedback on the whole process. – Edenshaw – 2019-01-02T13:06:43.540

7

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

Wink Saville

Posted 2009-10-27T19:46:06.483

Reputation: 71

I always used cp -r. Thanks for mentioning cp -a – Pinaki Mukherjee – 2017-06-19T18:40:19.800

5

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

simhumileco

Posted 2009-10-27T19:46:06.483

Reputation: 431

1

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 – 2018-09-06T17:53:17.263

@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 – 2018-09-06T22:30:33.153

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 – 2018-09-07T16:23:12.810

4

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

Posted 2009-10-27T19:46:06.483

Reputation: 41

4

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

Gabriel Hautclocq

Posted 2009-10-27T19:46:06.483

Reputation: 141

Or you could simply use cp -r /etc/skel /home/user for renaming skel to user... – David – 2013-09-13T12:46:39.513

That's right, only if /home/user does not exist yet. – Gabriel Hautclocq – 2013-10-14T11:52:34.150

3

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.

Linus

Posted 2009-10-27T19:46:06.483

Reputation: 31

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.

Rajneesh Gadge

Posted 2009-10-27T19:46:06.483

Reputation: 21

2

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

Posted 2009-10-27T19:46:06.483

Reputation: 241

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

Mikael Nyborg

Posted 2009-10-27T19:46:06.483

Reputation: 11

-2

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!

Fred James

Posted 2009-10-27T19:46:06.483

Reputation: 1

"a question box that pops up" — for a shell (CLI) command? – Scott – 2016-12-15T01:02:29.443