What is the added value of the -T option in GNU cp and mv?

Why do some GNU Coreutils commands have the -T/--no-target-directory option? It seems like everything that it does can be achieved using the semantics of the . (self dot) in a traditional Unix directory hierarchy.

Considering:

cp -rT /this/source dir

The -T option prevents the copy from creating a dir/source subdirectory. Rather /this/source is identified with dir and the contents are mapped between the trees accordingly. So for instance /this/source/foo.c goes to dir/foo.c and so on, rather than to dir/source/foo.c.

But this can be easily accomplished without the -T option using:

cp -r /this/source/. dir  # Probably worked fine since dawn of Unix?

Semantically, the trailing dot component is copied as a child of dir, but of course that “child” already exists (so doesn’t have to be created) and is actually dir itself, so the effect is that /this/path is identified with dir.

It works fine if the current directory is the target:

cp -r /this/tree/node/. . # node's children go to current dir

Is there something you can do only with -T that can rationalize its existence? (Besides support for operating systems that don’t implement the dot directory, a rationale not mentioned in the documentation.)

Does the above dot trick not solve the same race conditions that are mentioned in the GNU Info documentation about -T?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Your . trick can only be used when you’re copying a directory, not a file. The -T option works with both directories and files. If you do:

cp srcfile destfile

and there’s already a directory named destfile it will copy to destfile/srcfile, which may not be intended. So you use

cp -T srcfile destfile

and you correctly get the error:

cp: cannot overwrite directory `destfile' with non-directory

If you tried using the . method, the copy would never work:

cp: cannot stat `srcfile/.`: Not a directory

Method 2

The problem with cp/mv/ln as they were originally designed is that they’re two commands in one (copy to and copy into).

cp A B

is either copy A to B or copy A into B (copy A to B/A) depending on whether B exists and is a directory or not (and more variations if B is a symlink to a directory).

That’s bad because it’s ambiguous. So the GNU implementations have added options to work around that.

cp -T A B

copies A to B regardless. If B exists and is a directory, that will fail (unless you pass -r). In any case, you will not end-up with a A file inside B when you intended A to be copied to B.

And:

cp -t B A

is the copy into.

Method 3

The -T can provide a failure if a directory incorrectly exists for what should be a destination file:

$ mkdir mustbeafile
$ touch afile
$ cp -T afile mustbeafile
cp: cannot overwrite directory `mustbeafile' with non-directory
$ echo $?
1
$ cp afile mustbeafile
$

That is, instead of success-on-unexpected-copy-to-a-subdir, a warning and not-good exit status happens, which could then cause a script to abort, and human inspect why there’s a directory where there shouldn’t be one.

Method 4

Using a flag is also much clearer, and has less risk of unintended effects, when the command is used in a script instead of manually entered. Patching dots onto paths in a script could end up in all kinds of unexpected mischief.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x