When you copy using cp -a source/* target/
you are copying most of the files and directories from source
to target
. Specifically, the items that are excluded will probably be files beginning with a dot (.
) in the top level of source
.
Consider these files (or directories) in source
apple # will be copied
banana/ # will be copied, as will all its contents
.cherry # will not be copied
When you copy using cp -a source/. target/
you are copying the entire contents of source
, including any items beginning with a dot (.
) to target
Consider these files (or directories) in source
apple # will be copied
banana/ # will be copied, as will all its contents
.cherry # will be copied
If you're using bash
, zsh
, you can use the dotglob
option to change the meaning of *
so that it includes files and directories beginning with a dot (yash
also has a dotglob
option; however, it then includes .
and ..
in glob expansions which limits its usability. See also FIGNORE='@(.|..)'
in ksh93
).
Interestingly, cp -a source/. target/
is guaranteed never to create the component target/source
. (On the other hand, cp -a source target/
will do one of two things depending on whether or not target
already exists. See How to copy a folder recursively in an idempotent way using cp for the details.)
When you delete using rm -rf source/*
you are deleting the files and directories within source
that do not begin with a dot (.
). Subject to the dotglob
setting I've already mentioned. It will not delete the directory source
itself.
When you try to delete using rm -rf source/.
it will fail - as others have already explained - because POSIX prohibits deletion of a path whose last component is .
or ..
. The closest equivalent is rm -rf source
, which will delete the source
directory and all its contents regardless of whether or not they begin with a dot (.
).