1

i'm reading LPIC-1 PDF's. It says:

In general to copy all the contents of a directory we use:

cp -r SOURCE_PATH/* DEST_PATH

But i can't understand why -r option itself without * is not enough? It should be right?

Thanks.

Edit: i tried and results are interesting. First, if destination not exist, * wildcard in source gives error as there is no destination directory. Without * cp copies all hidden files including hidden in top and subdirectories.

On the other hand, if destination exist and we use * wildcard in source, cp copies all files in the top except hidden ones, but subdirectory hidden files included.

[rocky@rocky ~]$ tree -a test1
test1
├── .hiddentestfile1
├── test2
│   ├── .hiddentestfile2
│   └── testfile2
└── testfile1

1 directory, 4 files
[rocky@rocky ~]$ cp -r test1/* newdest
cp: target 'newdest' is not a directory
[rocky@rocky ~]$ cp -r test1/ newdest
[rocky@rocky ~]$ tree -a newdest
newdest
├── .hiddentestfile1
├── test2
│   ├── .hiddentestfile2
│   └── testfile2
└── testfile1

1 directory, 4 files
[rocky@rocky ~]$ rm -r newdest
[rocky@rocky ~]$ mkdir newdest
[rocky@rocky ~]$ cp -r test1/* newdest
[rocky@rocky ~]$ tree -a newdest
newdest
├── test2
│   ├── .hiddentestfile2
│   └── testfile2
└── testfile1

1 directory, 3 files
8
  • If the source directory contains subdirectories then -r is necessary to recursive through the tree.
    – doneal24
    Commented Sep 1, 2022 at 15:06
  • Have you set up a small example to test this for yourself?
    – Kusalananda
    Commented Sep 1, 2022 at 15:06
  • @doneal24 The question is regarding *, not -r.
    – Kusalananda
    Commented Sep 1, 2022 at 15:06
  • @Kusalananda Ok, I read the options backwards. Then adding the * to the source directory will generally exclude copying dot files.
    – doneal24
    Commented Sep 1, 2022 at 15:09
  • Thank you @doneal24 but Kusalananda is right. I know -r option. * has also same function. So is there any logical reason to use both together.
    – frknl
    Commented Sep 1, 2022 at 15:11

1 Answer 1

1
cp -r SOURCE_PATH/* DEST_PATH

Copies each of the (non-hidden) files or directories and their contents recursively into DEST_PATH (assuming that's a directory or symlink to directory).

Then if SOURCE_PATH contains for instance file, dir and .git, you end up with DEST_PATH/file and DEST_PATH/dir.

Beware that if DEST_PATH didn't exist or was not a directory and SOURCE_PATH contained only one non hidden file or directory (say SOURCE_PATH/file), then that would become cp -r SOURCE_PATH/file DEST_PATH (a copy-to instead of copy-into) which means DEST_PATH would be created (or overwritten) as a copy of file. Appending a / to DEST_PATH in the command ensures that doesn't happen (guarantees either a copy-into or failure with not a directory; see also the -t option of GNU cp).

With:

cp -r SOURCE_PATH DEST_PATH

You're copying the SOURCE_PATH directory (and all its contents recursively, including hidden files) into DEST_PATH (assuming again it exists and is a directory), so you end up with DEST_PATH/SOURCE_PATH, DEST_PATH/SOURCE_PATH/{.git,dir,file}. So it gives a different outcome altogether.

Here to copy all the contents of SOURCE_PATH (including hidden files) and not SOURCE_PATH itself into DEST_PATH, you'd rather use:

cp -r SOURCE_PATH/. DEST_PATH

Besides also including hidden files (which assuming zsh, you could also do with cp -r SOURCE_PATH/*(D) DEST_PATH/) that also has the advantage of not failing with a too many arguments error if SOURCE_PATH has too many non-hidden files, and not to report an error if SOURCE_PATH is empty. Also, if DEST_PATH doesn't exists it ends up being created as a copy of SOURCE_PATH.

With the GNU implementation of cp, you can do the same with:

cp -rT SOURCE_PATH DEST_PATH

(-T aka --no-target-directory forces a copy-to instead of a copy-into even when the destination is a directory).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .