cp -r 中的语法差异以及如何克服它们

cp -r 中的语法差异以及如何克服它们

假设我们位于一个空白目录中。然后,执行以下命令:

mkdir dir1
cp -r dir1 dir2

产生两个(空白)目录dir1dir2,其中dir2已创建为 的副本dir1。但是,如果我们这样做:

mkdir dir1
mkdir dir2
cp -r dir1 dir2

然后我们反而发现dir1现在已经被放入了里面dir2。这意味着完全相同的cp命令的行为有所不同,具体取决于目标目录是否存在。如果是,则该cp命令执行的操作与此相同:

mkdir dir1
mkdir dir2
cp -r dir1 dir2/.

这对我来说似乎非常违反直觉。我预计cp -r dir1 dir2(当dir2已经存在时)会删除现有的dir2(和任何内容)并将其替换为,因为这是用于两个文件dir1时的行为。cp我知道递归副本本身有点不同,因为 Linux 中目录的存在方式(更广泛地在类 Unix 系统中),但我正在寻找更多解释为什么选择了这种行为。如果您能向我指出一种确保cp其行为符合我预期的方法(无需事先测试并删除目标目录),那就加分了。我尝试了几个cp选项,但没有任何运气。我想我会rsync为了其他不知道该命令的人而接受解决方案。

如果这种行为不是普遍的,我在 CentOS 上使用 bash。

答案1

您正在寻找的行为是特例:

cp -R [-H|-L|-P] [-fip] source_file... target

[This] 形式由两个或多个指定了 -R 选项的操作数表示。 cp 实用程序应将每个 source_file 中的文件层次结构中的每个文件复制到名为如下的目标路径:

  • 如果 target 存在并命名现有目录,则文件层次结构中每个文件的相应目标路径的名称应为 target、单个<slash>字符(如果 target 不以 结尾<slash>)和文件相对于该目录的路径名的串联。包含 source_file 的目录。
  • 如果target不存在,且指定了两个操作数,则source_file对应的目标路径名称为target;文件层次结构中所有其他文件的相应目标路径的名称应是目标、字符<slash>和相对于 source_file 的文件路径名的串联。

如果目标不存在并且指定了两个以上的操作数,则应发生错误...

因此我想说这是不可能做cp你想做的事。


由于您的预期行为是“ cp -r dir1 dir2(当dir2已经存在时)将删除现有的dir2(和任何内容)并将其替换为dir1”:

rm -rf dir2 && cp -r dir1 dir2

您甚至不需要检查是否dir2存在。


解决方案是在源中rsync添加尾随,这样它就不会将自身复制到,而是将to的内容复制到(它仍将现有文件保留在 中):/dir1dir2dir1dir2dir2

$ tree dir*
dir1
└── test.txt
dir2
└── test2.txt

0 directories, 2 file
$ rsync -a dir1/ dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt
└── test2.txt

0 directories, 3 files
$ rm -r dir2          
$ rsync -a dir1/ dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt

0 directories, 2 files

答案2

cp 有几种形式:

   cp [OPTION]... [-T] SOURCE DEST
   cp [OPTION]... SOURCE... DIRECTORY
   cp [OPTION]... -t DIRECTORY SOURCE...

当您这样做时,cp -r dir1 dir2您期望对第二个参数进行隐式评估。

  • 如果第二个参数是文件系统中不存在的名称,cp 会将其解释为 DEST 并创建它,copyind dir1作为目录2。
  • 如果它已经存在,它将被解释为目录,从而复制 dir1进入它。

如果您不确定初始状态,并且想避免可能的多重解释,您可以简单地使用选项显式它-T

$ tree dir*
dir1
└── test.txt
dir2
└── test2.txt

0 directories, 2 file
$ cp -r dir1 -T dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt

0 directories, 3 files
$ rm -r dir2          
$ cp -r dir1 -T dir2
$ tree dir*           
dir1
└── test.txt
dir2
└── test.txt

0 directories, 2 files

相关内容