要将一个目录复制到另一个目录,第一个目录应该不带尾部斜杠:
# example 1
# this command will copy dir1 to dir2
# (dir2 is preexisting)
cp -Rip dir1 dir2/
否则,该命令将复制目录内容而不是目录本身:
# example 2
# this command will copy dir1 contents to dir2
# (dir2 is preexisting)
cp -Rip dir1/ dir2/
dir1
我确实理解和这里之间的区别dir1/
,并且这两个命令的行为方式之间的区别不会让我感到困惑。
但是,如果要将目录复制到当前所在的同一目录而不是另一个目录,则尾部斜杠不会产生任何区别。为什么?
# example 3
# any of these commands will make a dir1 copy
# (dir1-copy isn't preexisting)
cp -Rip dir1 dir1-copy/
cp -Rip dir1/ dir1-copy/
还有另一个密切相关的问题。为什么howmv dir1/ dir2/
和mv dir1 dir2/
work没有区别?换句话说,为什么源目录末尾的尾部斜杠mv
遵循示例三的逻辑cp
,而不是示例一和示例二的逻辑?
macOS 14.3.1、zsh 5.9 (x86_64-apple-darwin23.0)
答案1
cp -R dir1 dir2
和之间的行为差异cp -R dir1/ dir2
是 FreeBSD 中添加的一个功能5.4版本。至少,当时在手册中添加了以下句子来描述该-R
选项:
如果
source_file
以 / 结尾,则复制目录的内容而不是目录本身。
这种行为可能比较旧,5.4 只是填补了文档中的一个遗漏。里面没有这方面的内容5.0,5.1,5.2,5.3或者5.4发行说明。我还没有去源码潜水。
现代版本的 FreeBSD 和具有 FreeBSD 命令行实用程序的 macOS 保留了这种行为。其他系统(GNU、BusyBox、OpenBSD、NetBSD 或任何兼容 POSIX 的系统)没有此行为:cp -R dir1/ dir2
并且cp -R dir1 dir2
具有完全相同的行为(除非dir1
是符号链接:dir1/
导致链接被跟踪)。
FreeBSD 的行为可能受到 rsync 的启发,它也有同样的区别。我确实觉得很奇怪,他们做了一个向后不兼容的改变,偏离了
但是,如果要将目录复制到当前所在的同一目录而不是另一个目录,则尾部斜杠不会产生任何区别。为什么?
这是一个奇怪的设计决定。或者也许这不是一个设计决策,而是一个实现错误(解析源路径并确定尾部斜杠后面的部分是路径组件),他们决定调用一个功能。使用 rsync,即使目标目录不存在,尾部斜杠也会保持其行为。
mv dir1/ dir2/
为什么how和mv dir1 dir2/
work没有区别?
不应该有什么区别(假设dir1
不是符号链接),所以这只是正常情况。