26

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?

29

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
  • The . trick does work when copying a file, just not when renaming its basename at the same time! cp /path/to/file /target/dir/. If /target/dir/file exists and is a directory, you get the same diagnostic! But you have shown what -T does that can't be done without it in one step, without race conditions: copy a file and change its name without it being shunted to a subdirectory. – Kaz Jun 9 '16 at 20:54
  • 3
    That's not the same -- the . trick you're talking about is appending /. to the source. – Barmar Jun 9 '16 at 20:58
21

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.

  • The original unix philosophy is to assume you know what you do, and will happily allow you to shoot yourself in the foot. – Lenne Jun 10 '16 at 5:51
  • 4
    @Lenne, but here it doesn't give you a way to avoid shooting yourself in the foot. If someone creates a B directory or symlink to some directory just before you run cp A B the command will not do what you intended. And doing [ -e B ] || [ -L B ] || cp A B still has a race condition which cp -Tn A B doesn't have. – Stéphane Chazelas Jun 10 '16 at 5:57
6

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.

0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.