GNU cp 和 mv 中 -T 选项的附加值是什么?

Kaz*_*Kaz 26 cp coreutils

为什么有些 GNU Coreutils 命令有-T/--no-target-directory选项?似乎它所做的一切都可以使用.传统 Unix 目录层次结构中的(自点)语义来实现。

考虑:

cp -rT /this/source dir
Run Code Online (Sandbox Code Playgroud)

-T选项可防止副本创建dir/source子目录。而是/this/source被标识dir并相应地在树之间映射内容。因此,例如/this/source/foo.c转到dir/foo.c等等,而不是到dir/source/foo.c

但这可以很容易地完成,而无需-T使用以下选项:

cp -r /this/source/. dir  # Probably worked fine since dawn of Unix?
Run Code Online (Sandbox Code Playgroud)

从语义上讲,尾随点组件被复制为 的子级dir,但当然该“子级”已经存在(因此不必创建)并且实际上是dir它本身,因此效果是用/this/path标识的dir

如果当前目录是目标,它工作正常:

cp -r /this/tree/node/. . # node's children go to current dir
Run Code Online (Sandbox Code Playgroud)

有什么东西你只能-T它来合理化它的存在吗?(除了对未实现点目录的操作系统的支持,文档中未提及的基本原理。)

上面的点技巧是否不能解决 GNU 信息文档中提到的相同竞争条件-T

Bar*_*mar 30

您的.技巧只能在您复制目录而不是文件时使用。该-T选项适用于目录和文件。如果你这样做:

cp srcfile destfile
Run Code Online (Sandbox Code Playgroud)

并且已经有一个名为destfile它的目录将复制到destfile/srcfile,这可能不是故意的。所以你用

cp -T srcfile destfile
Run Code Online (Sandbox Code Playgroud)

你正确地得到错误:

cp: cannot overwrite directory `destfile' with non-directory
Run Code Online (Sandbox Code Playgroud)

如果您尝试使用该.方法,则副本将永远无法工作:

cp: cannot stat `srcfile/.`: Not a directory
Run Code Online (Sandbox Code Playgroud)

  • 这不一样——你所说的 `.` 技巧是将 `/.` 附加到 **source**。 (3认同)

Sté*_*las 22

这个问题cp/ mv/ln因为它们最初设计的是,他们两个命令在一个(拷贝复制到)。

cp A B
Run Code Online (Sandbox Code Playgroud)

将 A 复制到 B将 A 复制到 B将 A 复制到 B/A)取决于是否B存在并且是否是目录(如果 B 是目录的符号链接,则有更多变化)。

这很糟糕,因为它是模棱两可的。所以 GNU 实现增加了解决这个问题的选项。

cp -T A B
Run Code Online (Sandbox Code Playgroud)

无论如何都将 A 复制到 B。如果B存在并且是一个目录,那将会失败(除非你通过-r)。在任何情况下,当您打算复制B时,您都不会A在里面得到一个文件。BA

和:

cp -t B A
Run Code Online (Sandbox Code Playgroud)

复制到.

  • @Lenne,但在这里它并没有给你一种避免用脚射击自己的方法。如果有人在您运行 `cp AB` 之前创建了一个 B 目录或指向某个目录的符号链接,该命令将不会执行您的预期操作。并做`[ -e B ] || [ -LB ] || cp AB` 仍然有一个竞争条件,而 `cp -Tn AB` 没有。 (4认同)

thr*_*rig 6

-T可以提供故障如果不正确的目录存在什么应该是一个目标文件:

$ mkdir mustbeafile
$ touch afile
$ cp -T afile mustbeafile
cp: cannot overwrite directory `mustbeafile' with non-directory
$ echo $?
1
$ cp afile mustbeafile
$ 
Run Code Online (Sandbox Code Playgroud)

也就是说,不是在意外复制到子目录时成功,而是发生警告和不良退出状态,这可能会导致脚本中止,并且人工检查为什么存在不应该存在的目录成为一个。