为什么在 Linux 中复制目录时需要 -r 递归?

Mad*_*ent 48 linux cp

我的问题是为什么-r在制作目录副本时需要使用(递归)标志?即,为什么要这样做:

$ cp -r dir1 copyDir1
Run Code Online (Sandbox Code Playgroud)

复制目录时我什么时候不想要这种行为?

目录的递归副本不是真正的“默认”行为吗?我们几乎一直想要的行为?

感觉这是一个多余的标志。

Gia*_*968 59

文件系统的工作方式,目录实际上不是包含文件的文件夹,而是目录是包含指向连接到它的“子”文件的inode 指针的文件。这意味着,从文件系统的角度来看,文件是一个文件,而目录只是一个包含连接文件列表的文件。

所以从命令行的角度来看,这样做:

$ cp dir1 copyDir1
Run Code Online (Sandbox Code Playgroud)

基本上意味着将名为的文件复制dir1到名为copyDir1. 就文件系统而言,dir1无论如何都只是一个文件;它是一个“目录”的事实只有在文件系统实际检查dir1以查看那堆位实际上是什么时才会明显。

-r标志告诉文件系统递归地向下滚动文件/目录树,并将可能是该文件的“子”的任何和所有内容复制到新位置。

现在至于为什么这似乎是多余的或多余的,这实际上归结为处理文件系统的历史方法。以及创建一个可以避免所有类型的用户相关错误的系统;有意外也有故意。

意思是,假设~/bin您的主目录中有一个文件要复制,但不小心遗漏了 -~因为您是人并且会犯错误 - 所以它/bin就像这样:

cp /bin/ ~/copy_of_bin
Run Code Online (Sandbox Code Playgroud)

有了/bin作为目录的“安全网”以及对-r标志的需求,您将避免意外地将您所在系统的整个二进制根目录复制到您的主目录中。如果那个安全网不存在,就会发生轻微的——或者可能是重大的——灾难。

这里的逻辑是,在 GUI(图形用户界面)之前的时代,需要设置逻辑/行为约定,以避免用户创建可能导致系统崩溃的事故。-r现在使用标志就是其中之一。

如果这看起来是多余的,那么只需看看可以放在 Linux 文件系统之上的现代 GUI 系统。GUI 通过允许用户轻松拖放文件和目录来解决此类基本用户问题。

但在基于文本的界面领域,该世界中的许多“用户体验”基本上只是基于逻辑和色调的道路颠簸,有助于让用户保持控制,从而避免潜在的灾难。

类似地,这就是为什么 Linux/Unix 文件系统没有默认设置的777权限和sudo权限,以及当用户设置777权限或授予每个sudo人权限时,真正的系统管理员如何畏缩。这些是确保系统稳定和尽可能“用户证明”的基本事情;任何急于打破这些约定的人很可能在不知情的情况下对他们的系统造成损害。

附加信息: Unix Stack Exchange 站点上的另一个答案很好地解释了为什么目录的非递归副本有问题;重点是我的。

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

因此,如果一个目录实际上只是一个包含 inode 项的文件,那么直接复制该文件就相当于硬链接的工作方式。这不是任何人想要的。

  • 我个人认为它的“保护”方面没有通过气味测试。有些人可以像输入“cp-r ~/bin”一样轻松地输入“cp -r /bin”。旗帜本身并不能防止错误,也不能使任何人变得更加小心。如果你想防止错误,cp 命令可以很容易地查看有问题的节点并提供一个提示,类似于“这是一个目录,你想将所有内容复制到指定位置吗(y /n)?” **那**将是**_安全网_**。对目录要求 -r 比任何事情都更能减少代码膨胀。 (21认同)
  • 与沙井的类比不好。正如@JDL 所说,有问题的标志对防止路径中的拼写错误没有任何作用。我更乐意接受与其他命令的一致性作为一个原因,但我有一种感觉,真正的原因是“它最初是这样编写的,现在很多东西都依赖于这种行为,改变它是不可能的”。 (12认同)
  • 当我们**移动**一个目录时,我们**不需要** -r。我认为 unix.stackexchange.com 上的链接答案更重要。**非递归副本的等价物是拥有第二个目录,以及目录树中所有文件的硬链接。** (7认同)
  • 如果我没记错的话,-r 是一个 GNU 扩展——我不认为历史上的 UNIX cp _had_ 是一个递归副本——这是命令 _rsync_ 的部分原因。 (2认同)
  • @JakeGould 我了解基本概念。但是,我反对在相关命令上使用 -r 标志提供任何额外安全性的想法。根据我的经验,命令行 linux 命令在历史上本质上是不安全的。如果有的话,加班时间增加了安全性。linux 设计中固有的安全性来自权限系统和放弃以 root 身份运行。不以 root 身份运行也是一种约定,而不是设计。大多数新的 linux 安装程序都支持该约定,但并非总是如此。 (2认同)

loo*_*bee 19

确实,这是我们几乎一直想要的行为。但是,这并不一定意味着递归复制应该是默认行为。

我认为原因cp确实源于Unix 哲学。Unix 偏爱只做一件事并把它做好的程序,以及接口和实现简单的程序(有时称为越糟越好)。

这里难题的关键部分是意识到cp不复制目录 -cp复制文件(并且复制文件)。如果要复制目录,cp 递归调用自身,以便复制每个目录上的文件。

当然,从用户的角度来看,“复制目录”和“递归复制文件”之间的区别是绝对没有的,但是拥有这个接口有助于实现保持简单

如果您cp能够复制目录,您很快就会想添加更多仅对目录有意义的功能 - 例如,您可能只想复制以.sh. 不可避免地,这会导致我们在其他操作系统中习惯的膨胀功能蠕变——使软件变得缓慢、复杂和容易出错。

另一个优点是-r还可以帮助用户了解界面下真正发生的事情。这样做的一个很好的副作用是,当您了解支持递归操作的其他工具(例如grep,例如)时,学习递归操作的概念将为您节省一些工作


有些人肯定会告诉你,将实现细节暴露给用户是不好的,拥有更多的特性是好的。我在这里的目的只是解释这种行为的基本原理,所以我不会试图以任何方式争论。

  • +1 **“……做一件事,把它做好……”**谢谢你的陈述! (2认同)

mbb*_*mbb 5

与目录的交互确保您知道您正在与目录交互,而不仅仅是与单个文件交互。

例如:

$ tree
.
??? folder1
    ??? sub1
        ??? subsub1

3 directories, 0 files
$
$ cp folder1/ folder2
cp: folder1/ is a directory (not copied).
$
$ mkdir blah
$ cp blah/ blah2
cp: blah/ is a directory (not copied).
$ rm blah/
rm: blah/: is a directory
Run Code Online (Sandbox Code Playgroud)

因此,如果您想成功复制文件夹,因为它意味着文件夹和与引用文件夹相关的对象,您必须将其视为文件集合:

$ cp -r folder1/ folder2
$ rm -rf folder1
Run Code Online (Sandbox Code Playgroud)


小智 5

该标志的一个明显优点-r是您可以仅将源目录中的所有文件cp * /target/dir复制到目标目录中,忽略(尽管有警告)其中包含的所有目录。会复制所有内容,包括子目录。cp -r * /target/dir