为什么 unix mv 程序不需要目录的 -R(递归)选项但 cp 确实需要它?

wob*_*ene 64 directory cp rename

我总是在需要使用时搞砸cpmv:“-R使用 dir 时我需要选项吗?” 在GNU的coreutilscp确实需要-Rmv不。

我只是找不到任何cp需要-R复制目录选项的原因,而mv没有。我认为,cp荷兰国际集团迪尔斯没有-R(但递归表现像有-R和喜欢mv一样)不会引起除了打破该工具的使用人的使用习惯的任何问题。

你知道有什么解释吗?可能是很久以前的原因?


附加问题:为什么 coreutils 开发人员cp默认情况下不递归复制目录?

der*_*ert 46

目录(概念上)是一个特殊的“文件”,其中包含名称列表以及这些名称指向的 inode 编号。一些名称可以是子目录。有一个..指向父目录的特殊条目。

因此,很明显,更改文件名很容易:您只需更改目录条目中的名称,无需其他任何操作。这保存文件实际上是一个文件,还是用于存储另一个目录内容的“文件”。事实上,同一个rename系统调用同时完成了这两个任务。

然而,复制是一个不那么简单的操作。您可以只复制目录“文件”,但是您将有两个文件相同的目录(它们是硬链接)。如果您有一个允许硬链接到目录的系统,那将是,但由于没有现代系统允许这样做,至少对于非 root 用户,您必须为每个子目录进行复制。您实际上可以cp使用cp -lR:-l对于硬链接,-R对于该递归来请求这种行为。

但让一切都联系起来可能不是你想要的。相反,您想要cp复制每个文件。这是一个相当昂贵的操作:每个文件都必须读入内存,然后写回到磁盘的第二个位置。它实际上需要几个系统调用来打开、读取、写入和关闭文件,并且必须对每个文件重复。

传统的文件系统在磁盘上也以这种方式工作。没有任何方法可以复制一堆文件,除了单独遍历每个文件并复制它之外,这些是设计基本命令行实用程序时使用的文件系统类型。

  • 我可以告诉你,从直接经验而不是猜测,经典的`mv`不支持跨设备移动。它曾经只是尝试一个 `rename()` 并在失败时打印一条错误消息。我仍然记得我第一次不小心使用新功能时的震惊感觉。为什么这个 mv 需要这么长时间?哦,它正在做一个我不想要的递归复制! (9认同)
  • 不,跨文件系统与复制 + 删除相同(实际上,跨文件系统的 `rename` 系统调用将失败)。不确定从历史上看,`mv` 是否甚至支持跨 fs 移动。 (5认同)
  • @RuslanKhusnullin 常用命令的命令行选项很难更改,因为它们在 shell 脚本中使用。有人可能会依赖于当前 cp 的拒绝复制目录行为。cross-fs 的东西可能被认为不太可能导致破损,但正如你所看到的,它仍然让 Alan 感到惊讶。 (5认同)

dan*_*ann 21

让我先问另一个问题:

cp和 和有cp -R什么区别?

好吧,没有-R标志,只能复制文件,因为有人想要非递归复制目录是很不寻常的:非递归复制只会导致目录的第二个名称,直接指向同一目录结构体。因为这很少是人们想要的,而且实际上有一个单独的程序可以执行此操作 ( ln),因此不允许目录的非递归副本。

那么mv和之间可能有什么区别mv -R

mv a b只重命名目录中的单个条目,因此如果目录被mv编辑,其内容也会自动移动。从这个意义上说,mv已经提供了递归属性,即重命名目录中所有条目的“重命名”,例如 from a/1to b/1。Amv不这样做,即将目录重命名ab,但保持a/1a/1,这不是人们在提及移动某物时所理解的:当您移动橱柜时,橱柜的内容也会随之移动。移动没有内容的目录的其他操作也已经可用,称为mkdir.

  • 没错,我只是将 `cp` 和 `mv` 视为它们被命名的操作:“制作副本”和“移动”。因此,如果我想制作一杯咖啡的副本,我希望再喝一杯同样馅料的咖啡(咖啡饮料)。问题是这些工具不是为“普通人”准备的,而是为那些了解磁盘和文件系统结构的书呆子准备的,而不是像文件和文件目录这样的虚拟实体。 (2认同)

wob*_*ene 6

通常,当我对 Unix 逻辑感到困惑时,我会查看 Plan9,以了解 Unix 发明者如何在多年后实现相同的任务而不坚持向后兼容性。

所以Plan9相关的优惠cpmv工具,只用文件进行操作。

`cp f1 f2` creates f2 and copies f1's contents into it.
`mv f1 f2` renames f1 to f2 if f1 and f2 are in the same dir
           does `cp f1 f2 && rm f1` else
           can rename dirs (`mv d1 d2`) but will not move dir to another dir.
Run Code Online (Sandbox Code Playgroud)

对于复制目录dircp,实际上是@{cd fromdir && tar c .} | @{cd todir && tar xT}(rc shell 语法)

对于移动目录,我认为只有 dircp d1 d2 && rm -r d1

我认为这个限制cpmv仅用于文件操作(不是目录)的决定使磁盘操作更加清晰,并且tar用于复制文件树对于理解和编写脚本非常方便。