为什么“cp -ra/. b”的行为如此?

为什么“cp -ra/. b”的行为如此?

我以为aa/.是同一条路径。然而,我发现cp同步/.当添加到源路径时,复制目录内容而不是目录本身。我也试过了a/inner/..;这也奏效了。

$ cp -r a b  # Copies dir a into dir b.
$ cp -r a/. b  # Copies files from dir a into dir b.
$ cp -r a/inner/.. b  # Also copies files from dir a into dir b.
$ cd a && cp -r . ../b  # One more way to copy inner files.

我知道这很有用。但我有点困惑,因为这个功能似乎违反了标准。

这是如何工作的?这个功能在某处有记录吗?这是操作系统的一个功能吗?cp还是 bash?

答案1

我知道这很有用。但我有点困惑,因为这个功能似乎违反了标准。

cpa/.从到递归复制时的行为b与其“正常”行为完全一致。

默认情况下,cp不会创建父目录。可以使用父母转变:

   --parents
          use full source file name under DIRECTORY

但是,这是什么意思?

这意味着虽然命令

cp --parents -r some/path/to/source dest

将源目录的内容复制到dest/some/path/to/source命令中

cp -r some/path/to/source dest

将会把源目录的内容复制到 中dest/source

同样,命令

cp -r some/path/to/source/. dest

会将源目录的内容复制到中dest/.,也就是dest

我以为aa/.是同一条路。

aa/. 相同的路径。但作为论据cp,它只是一个字符串。

请注意命令

cp --parents -r some/path/to/source dest

cd some/path/to && cp --parents -r source dest

也会表现不同。


那怎么样cp -r a/inner/.. b?考虑到您的解释,它不应该将文件复制到b/..(即复制到当前目录)吗?

嗯,是的。这是个例外。

至少在 GNU 版本中cp,对于基本名称,有一个特殊情况..

coreutils-8.22/src/cp.c

          if (parents_option)
            {
              [removed]
            }
          else
            {
              char *arg_base;
              /* Append the last component of 'arg' to 'target_directory'.  */

              ASSIGN_BASENAME_STRDUPA (arg_base, arg);
              /* For 'cp -R source/.. dest', don't copy into 'dest/..'. */
              dst_name = (STREQ (arg_base, "..")
                          ? xstrdup (target_directory)
                          : file_name_concat (target_directory, arg_base,
                                              NULL));
            }

其动机似乎是为了避免复制到目标文件夹之外,尽管这与cp在其他情况下的行为有点违反直觉,并且可能会产生不愉快的后果。

毕竟,我认为没有人会想到这个命令

cp -r .. ~

影响他的主目录之外的文件......

答案2

$ mkdir a b a/inner
$ touch a/a{1..3} b/b{1..3}
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3
$ cp a b
cp: omitting directory ‘a’
$ cp a/. b
cp: omitting directory ‘a/.’
$ cp a/inner/.. b
cp: omitting directory ‘a/inner/..’
$ cd a && cp . ../b
cp: omitting directory ‘.’
$ cd ..
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3

您所说的事情实际上都没有发生。这四个cp命令什么都不做。也许您有一个 loaded 的别名cp。您可以使用 来检查这一点alias cp

答案3

顺便rsync(1)读一下它的手册小心。它使用了一些不寻常的约定来表示“目录的内容”而不是“目录及其内容”。

对于cp(1)和其他 Linux 命令,核心levela甚至引用完全相同的目录。这并不意味着应用程序不能自行解析它们并赋予它们不同的意义,但将字符串发送给内核会更简单,内核会做正确的事情a/.a/inner/..

答案4

如果我没记错的话,我相信这个例子中的 . 的作用类似于 *。本质上是一个通配符。

相关内容