cp --no-target-directory explained
Solution 1
By default, cp
tests if its last argument is an existing directory. If this happens, cp
creates a link inside that directory, with the base name of the source. That is, given the command
cp foo/bar wibble
if wibble
is an existing directory then cp
copies the source to wibble/bar
. If wibble
does not exist then cp
links the source to wibble
.
If you want to be sure that the copy is always wibble
, then you can specify the --no-target-directory
(alias -T
) option. That way, if cp
succeeds, you can be sure that the copy is called wibble
. If wibble
already existed as a directory, then cp
will fail.
In tabular form:
The target is … Without -T With -T
existing directory copy in the directory error
existing file (not dir) overwrite overwrite
does not exist create create
The only difference is that with -T
, in case the target is an existing directory, the command returns an error. This is useful when you expect the directory not to exist: you get an error message instead of something unpredicted happening.
The same applies to mv
and ln
. If the target is an existing directory, with -T
, they signal an error rather than silently doing something different.
With cp
, there's a different case. If you do a recursive copy and the source is a directory, then cp -T
copies the content of the source into the destination, rather than copying the source itself. That is, given
$ tree source destination
source
└── foo
destination
└── bar
then
$ cp -rv source destination
`source' -> `destination/source'
`source/foo' -> `destination/source/foo'
whereas
% cp -rvT source destination
`source/foo' -> `destination/foo'
Solution 2
You would use --no-target-directory
if you don't want a source
directory copied underneath an existing destination directory, you
want the source directory copied onto the destination directory.
Here is an example of a directory copy with and without --no-target-directory
:
$ mkdir a
$ touch a/b a/c
$ find
.
./a
./a/c
./a/b
$ cp -r a b # b does not exist; becomes copy of a
$ find
.
./b
./b/b
./b/c
./a
./a/c
./a/b
$ rm -r b
$ mkdir b
$ cp -r a b # b already exists; a is copied *underneath* it
$ find
.
./b
./b/a
./b/a/b
./b/a/c
./a
./a/c
./a/b
$ rm -r b
$ mkdir b
$ cp -r --no-target-directory a b # b already exists; becomes copy of a
$ find
.
./b
./b/b
./b/c
./a
./a/c
./a/b
You can achieve something of the same effect by suffixing the source
directory name(s) with slash-dot /.
as in: cp -r a/. b
which copies
source directory a
onto b
and not underneath b
.
Neither of the above methods are the same as saying "copy only the contents of the source directory to the existing destination" since, if you ask to preserve time and permissions, the existing destination directory will acquire the time and permissions of the source directory. An example (edited to remove unnecessary information):
$ find . -ls
drwx------ Oct 13 13:31 ./b # note date and permissions
drwxr-xr-x Jan 1 2013 ./a # note date and permissions
-rw-r--r-- Oct 13 13:23 ./a/c
-rw-r--r-- Oct 13 13:23 ./a/b
$ cp -rp --no-target-directory a b # preserve mode and timestamps
$ find . -ls
drwxr-xr-x Jan 1 2013 ./b # note copied date and permissions
-rw-r--r-- Oct 13 13:23 ./b/b
-rw-r--r-- Oct 13 13:23 ./b/c
drwxr-xr-x Jan 1 2013 ./a
-rw-r--r-- Oct 13 13:23 ./a/c
-rw-r--r-- Oct 13 13:23 ./a/b
A content-only copy would not transfer the mode or timestamps of the source directory to the destination directory.
Solution 3
How about the following?
$ cp -rvT Dir_1 Dir_2
‘Dir_1/File_3.txt’ -> ‘Dir_2/File_3.txt’
‘Dir_1/File_1.txt’ -> ‘Dir_2/File_1.txt’
‘Dir_1/File_2.txt’ -> ‘Dir_2/File_2.txt’
$ cp -rv Dir_1 Dir_2
‘Dir_1’ -> ‘Dir_2/Dir_1’
‘Dir_1/File_3.txt’ -> ‘Dir_2/Dir_1/File_3.txt’
‘Dir_1/File_1.txt’ -> ‘Dir_2/Dir_1/File_1.txt’
‘Dir_1/File_2.txt’ -> ‘Dir_2/Dir_1/File_2.txt’
As such, it's just a different way of writing cp Dir_1/* Dir_2/
. However, it does catch hidden files at the root of Dir_1 that would be missed by a simple cp *
.
$ touch Dir_1/.Hidden_File_{1,2,3}.txt
$ cp -rv Dir_1/* Dir_2
cp: No match.
$ cp -rvT Dir_1 Dir_2
‘Dir_1/.Hidden_File_2.txt’ -> ‘Dir_2/.Hidden_File_2.txt’
‘Dir_1/.Hidden_File_3.txt’ -> ‘Dir_2/.Hidden_File_3.txt’
‘Dir_1/.Hidden_File_1.txt’ -> ‘Dir_2/.Hidden_File_1.txt’
Related videos on Youtube
Comments
-
erch almost 2 years
Question: I need a simple example of how to use
cp --no-target-directory
.I do experience some difficulties in understanding
cp --no-target-directory
. I do understand the explanation formv --no-target-directory
, but I can't really imagine a way to use it forcp
.For example, when the command
mv /tmp/source /tmp/dest
succeeds, there is no guarantee that/tmp/source
was renamed to/tmp/dest
: it could have been renamed to/tmp/dest/source
instead, if some other process created/tmp/dest
as a directory. However, ifmv -T /tmp/source /tmp/dest
succeeds, there is no question that/tmp/source was renamed to
/tmp/dest`. (source) -
erch over 10 yearsworks for me with[out]
--no-target-directory
option: as long as I use --recursive, everything is fine [withcoreutils 8.12
under GNU/Linux]. The main difference seems to be that with--no-target-directory
the content but not the directory itself is copied [research still in progress]