`/usr` 目录的理念是什么?

"Unix系统资源"或者说"/usr"目录的理由是什么?它在根目录"/"下面重复了很多目录名,具体描述可以参考这里
我的目的是:我正在第n次安装Oracle JDK,并决定这一次将其放在"/home/user"目录下。我只是随便看看,想知道在单用户机器上这样做是否是个坏主意。

2你的主目录是一个非常适合安装第三方软件的地方,而且不需要使用root权限。 - Lekensteyn
18多年来,你一直以为/usr是一个隐藏的“用户”目录,但如今你终于意识到这是个令人沮丧的错误。 - Govind Rai
14我一直以为这是“用户”。就像用户二进制文件一样。 - Tanner Babcock
@TannerBabcock 我认为是这样的。至少我认为/usr/bin 是用来安装系统范围的非必要系统二进制文件的地方。 - Aslan French
1个回答

有你回答的简短版本和长版本...
历史
简短版本:
正如您的链接所述,/usr是用于系统范围的只读文件的位置。因此,所有安装的软件都放在那里。它不会复制/的任何名称,除了/bin和/lib,但最初目的不同:/bin和/lib仅用于引导所需的二进制文件和库,而/usr/bin和/usr/lib用于所有其他可执行文件和库。(现在请不要问/sbin,毕竟这是简短版本)
如今,引导所需和非必需之间的区别已经模糊化了,因为大多数现代发行版(包括Ubuntu)在没有来自/usr目录下的几个文件的情况下无法正常启动。这就是为什么有一个强烈的合并"/usr/bin"和"/bin"的趋势。从Ubuntu 19.04开始,/bin,/lib(以及/sbin)只是它们对应的/usr中的符号链接,而自Ubuntu 20.04起,它们甚至不存在了。
但也许你把/usr和/usr/local混淆了?因为是的,存在(并且应该存在)很多重复的目录名称。稍后会详细解释...
长篇版本:
70年代初,Unix操作系统(是的,Unix在Linux之前)的磁盘空间很小(还没有硬盘!),在某个时候,系统二进制文件的数量和大小增长到无法放入单个磁盘的程度,开发人员不得不将它们分割到多个介质上,并为它们创建新的挂载点。/bin文件系统已满,所以他们将新的二进制文件安装在.../usr/bin目录下。而当时,/usr目录实际上是他们的用户目录!
在这次分割发生后,这几乎是令人尴尬的事情,通常被当作一个笑话或传说来讲述,他们开始创造人为的理由和标准来决定哪些应该放在/bin目录下,哪些应该放在/usr/bin目录下。非正式的规则是:“必要的”东西放在/bin目录下,“其余的”放在/usr/bin目录下。/lib目录也是如此。不久之后,/usr目录变得拥挤,系统相关的目录与实际用户的家目录混合在一起。因此,/home目录诞生了,用于存放所有与用户相关的目录,使/usr目录保持“系统相关”的干净。
这是在FHS存在之前的事情。当它被创建时,它接纳并正式化了当前的传统,并保留了名称/usr,尽管那时它已经与"用户"没有任何关系了。所以是的,像"UNIX Source Repository"或"UNIX System Resources"这样的花哨名字都是虚构的名字,而且现在改名已经太迟了。但是,正如我们所见,把/bin/lib/sbin扔进去还不算晚。所以/usr现在是主要的"系统"目录。 "好的,那/usr/sbin呢?",你问道。该死,我希望你忘了。好吧... /usr/sbin用于只能(或者仅在)由root用户执行的命令,比如mountfdisk

"但这不是和/bin几乎一样吗?" 是的,没错,但是...

"等等,那为什么还有一个/sbin呢?这一点都没有意义!" 嗯,那是因为... 呃... 等一下...

看,你身后有只三头猴子!

好了,希望你已经分心了。继续说下去...

如果你认为我在作弊,是的,我确实在作弊。但是"官方"答案也是如此: "必须由root执行并且在挂载/之前就要可用的关键命令。" 什么?别闹了!事实上:界限确实模糊不清,还有很多遗留的名称和路径只是"卡住"了,现在很难摆脱。

更多关于合并/usr目录的理由,来自systemd文档:

历史上将/bin、/sbin和/lib与/usr分开的理由在今天已不再适用。它们被拆分出来是为了将一些选定的工具放在更快的硬盘上(因为当时硬盘较小,价格更高),并包含挂载较慢的/usr分区所需的所有工具。如今,在早期引导过程中,initramfs已经必须挂载一个单独的/usr分区,因此对于拆分的理由已经没有意义。此外,现有状态下/bin和/sbin中的许多工具已经失去了在没有预先挂载的/usr情况下运行的能力。再也没有有效的理由将操作系统分散在多个层次结构中,它已经失去了其目的。
关于/usr拆分及其原理的精彩阅读,请参考Rob Landley的文章:
Understanding the bin, sbin, usr/bin , usr/sbin split

现今

目前,关于安装目录,你最好的理解方式是这样思考:

  • /usr - 所有由操作系统安装或提供的系统范围内的只读文件。

  • /usr/local - 由本地管理员(通常是您)安装的系统范围内的只读文件。这就是为什么大多数来自/usr的目录名称在这里重复的原因。

  • /opt - 一个用于系统范围内的只读和自包含软件的灾难。也就是说,这些软件不会像规范良好的软件那样将文件分散在binlibshareinclude等目录中。

  • ~/.local - /usr/local的每个用户对应目录,即每个用户安装的软件。与/usr类似,它有自己的~/.local/share~/.local/bin~/.local/lib目录。

  • ~/.local/opt - /opt的每个用户对应目录。

那么软件应该安装在哪里呢?

上面的列表已经给出了你关于Oracle JDK问题的一半答案,至少它提供了几个线索。关于“我应该在哪里安装软件X?”的检查清单如下:

  • 如果它是一个完全自包含的、单个目录的软件,像Eclipse IDE和其他下载的Java应用程序一样,并且您希望它对所有用户都可用?那么请安装在/opt目录下。

  • 与上述情况相同,但您不关心其他用户,只想为您自己安装?那么请安装在~/.local/opt目录下。

  • 如果它的文件分散在多个目录中,例如binshare,就像使用./configure && make && sudo make install编译和安装的传统软件一样,并且应该对所有用户都可用?那么请安装在/usr/local目录下。

  • 与上述情况相同,但只针对您自己的用户安装?那么请安装在~/.local目录下。

  • 由操作系统或软件包管理器(如软件中心)安装的软件,最重要的是,任何本地修改可能会在更新管理器升级到新版本时被覆盖?那么请安装在/usr目录下。

注:

这就解释了为什么编译软件的默认安装前缀是/usr/local,以及为什么在只为自己的用户安装软件时应将其更改为./configure --prefix=$HOME/.local
您可能已经注意到,上述所有目录都是只读的(当然,在安装/删除软件时除外)。可写文件(如配置文件)通常存储在/etc(用于系统范围的软件)和~/.config(用于每个用户的设置)中。尽管许多传统软件(不幸的是,一些现代软件也是如此)仍然使用~/.<software-name>,在您的主文件夹根目录中堆积了数十个隐藏的目录和文件。 ~/.local~/.config不是FHS规范的一部分。FHS不涉及用户的主文件夹。它们是Freedesktop/XDG的一次尝试,该组织面向桌面环境(如Gnome、KDE和Unity),试图制定一些关于用户主文件夹结构的约定。并非所有软件都遵循它(例如,发行版最近才将~/.local/bin包含在用户的默认$PATH中,仅当它存在时),并且没有用户被强制遵循它,但如果他们这样做,两者都会获得许多互操作性的好处。
希望这能稍微澄清一些事情。随时提问,以便我可以改进答案!
(我也希望纯粹主义者不要因为如此非常非正式的语言和解释而批评我。这是有意为之的,肯定存在许多不准确之处,但我相信这是让新手对安装目录的原理有一个简要概述的好方法)

2你总结得非常简洁,没错,完整的答案比上面的内容要长得多! - papashou
为什么不呢?同样的逻辑适用:攻击者可能在用户主目录或其子目录下创建一个以系统命令命名的可执行文件。 - ignis
3@ignis:如果攻击者可以在用户的主目录下创建和修改文件,那么该用户已经完全被入侵了,$PATH是无关紧要的。攻击者甚至可以通过~/.profile来改变它,所以你的观点是无意义的。~/.local/bin~/bin一样安全(或者说不安全,如果你愿意),这在大多数发行版中都是常见做法。认为用户不应该在$PATH中保留和执行个人脚本的任何目录是荒谬的。 - MestreLion
因此,~/bin~/.profile 一样安全,而 $PATH 不能保护我免受由我自己运行的恶意软件的侵害(该恶意软件具有在我的个人目录中写入的权限)。我之前不知道这个文件,对此我感到抱歉。谢谢你的解释,对我之前的评论表示道歉。 - ignis
历史越悠久,改进与混乱就越多。 - smwikipedia
1感谢您详细的回答!当前版本有任何更新吗?17.04? - danfromisrael
2这个回答就像一次旅程!这个人太牛了 :) - Jacek Dziurdzikowski
@danfromisrael:17.04(或2022年)没有什么大新闻:XDG标准现在被更广泛采用,并且在规范中有更多的目录,例如运行时和状态,/opt也更常见,并且还有自包含的_snaps_,但是现如今部分仍然保持不变。 - MestreLion