原文:The Linux Philosophy for SysAdmins
协议:CC BY-NC-SA 4.0
一、Linux 理念简介
Unix 哲学是使 Unix 1 独特而强大的重要部分。已经有很多关于 Unix 哲学的文章。而且 Linux 哲学本质上与 Unix 哲学是一样的,因为它是 Unix 的直系后裔。
最初的 Unix 哲学主要是为系统开发人员设计的。事实上,以肯·汤普森 2 和丹尼斯·里奇 3 为首的 Unix 开发者以一种对他们有意义的方式设计了 Unix,创建了规则、指导方针和过程方法,然后将它们设计到操作系统的结构中。这对于系统开发人员来说很有效,对于系统管理员来说至少部分有效。这些来自 Unix 操作系统创始者的指导被整理成了一本优秀的书,由 Mike Gancarz 所著的《Unix 的哲学》,随后被 Gancarz 先生更新为《Linux 和 Unix 的哲学》。 4
**Eric S. Raymond 的另一本好书《Unix 编程的艺术》提供了作者在 Unix 环境中编程的哲学观点。它在某种程度上也是作者所经历和回忆的 Unix 发展史。这本书的全文也可以在网上免费获得。 6
我从这三本书中学到了很多。它们对 Unix 和 Linux 程序员都有很大的价值。在我看来, Linux 和 Unix 哲学和Unix 编程的艺术应该是 Linux 程序员、系统管理员和开发人员的必读书目。
我从事计算机工作已经超过 45 年了。天哪,那是很长的一段时间!直到我开始使用 Unix 和 Linux,并开始阅读一些关于 Unix、Linux 和它们共享的共同理念的文章和书籍,我才理解为什么 Linux 和 Unix 世界中的许多事情都是这样做的。
在撰写本文时,我已经在 Unix 和 Linux 上工作了 20 多年,我发现 Linux 哲学极大地提高了我作为一名系统管理员的效率和效力。我总是试图遵循 Linux 哲学,因为我的经验是,不管一大群头发尖尖的老板(PHB)施加多大的压力,严格地坚持它,从长远来看总是会有回报的。
最初的 Unix 和 Linux 理念是为那些操作系统的开发者准备的。尽管系统管理员可以将许多原则应用到他们的日常工作中,但是许多重要的原则,特别是对于系统管理员来说,却是缺失的。
在我的 Unix 和 Linux 职业生涯中,我很幸运有几个优秀的导师。他们帮助我获得了失败的信心。当我失败时,我学到的比事情顺利时要多得多,因为他们让我解决了自己给自己带来的问题。这些专家,比我有更多年系统管理员经验的人,从来没有因为我失败而斥责我或惩罚我——他们的信条是,“如果你失败了,你就会学到东西。”我学到了很多。他们教给我的很大一部分是 Linux 哲学,但他们也教给我他们自己的哲学,这些哲学有助于填补原著中缺失的部分。
因此,在我从事 Linux 和 Unix 工作的这些年里,我形成了自己的哲学——它更直接地适用于系统管理员的日常生活和任务。我的哲学部分基于最初的 Unix 和 Linux 哲学,以及我的导师的哲学。当我决定写我自己的书,一本旨在解决当今系统管理员的需求的书时,我从那些原则开始,但是随着我的进步和这本书的结构向我展示,哲学的结构和本质变得比以往任何时候都更加清晰。事实证明,这种哲学与最初的 Linux 哲学有很大的不同。直到那时,我才意识到需要一种新的哲学,一种专门针对系统管理员的哲学。很自然地,我把这种新哲学称为“系统管理员的 Linux 哲学”
这本书是我创造新哲学的成果——它提供了成为更好的系统管理员的独特的实践方法。这本书和它所揭示的哲学是我试图回馈在我成长过程中养育我并帮助我变得更加自信的社区。
因为“系统管理员的 Linux 哲学”这个名字有点长,为了简单起见,在本书中大多数时候我将它称为“哲学”。
我是系统管理员吗?
因为这本书是为系统管理员准备的,所以知道你是否是一名系统管理员会对你有所帮助。维基百科 7 将系统管理员定义为“负责维护、配置和可靠运行计算机系统的人;尤其是多用户计算机,比如服务器。”根据我的经验,这可能包括计算机和网络硬件、软件、机架和机箱、机房或空间等等。
典型的系统管理员的工作可能包括大量的任务。在小型企业中,系统管理员可能负责所有与计算机相关的事情。在较大的环境中,多个系统管理员可能共同负责保持系统运行所需的所有任务。在某些情况下,您可能甚至不知道自己是系统管理员;你的经理可能只是告诉你开始维护办公室里的一台或多台电脑——不管你喜不喜欢,这都会让你成为一名系统管理员。
还有一个术语“DevOps”,用于描述以前分离的开发和运营组织的交集。在过去,这主要是教系统管理员编写代码,但现在的重点转移到教程序员如何执行操作任务。参与系统管理员的任务使这些人也成为了系统管理员,至少在一部分时间是如此。当我在思科工作时,我有一份 DevOps 类型的工作。一部分时间我编写代码来测试 Linux 设备,其余时间我在测试这些设备的实验室中担任系统管理员。这是我职业生涯中非常有趣和有意义的一段时间。
我创建了这个简短的列表来帮助你确定你是否是一个系统管理员。你知道你是一个系统管理员,如果…
-
你认为这本书可能是一本有趣的读物。
-
人们经常请你帮助他们使用电脑。
-
你每天早上在做其他事情之前都要检查服务器。
-
您编写 shell 脚本来自动化甚至简单的任务。
-
您共享您的 shell 脚本。
-
您的 shell 脚本获得了开源许可。
-
你知道开源意味着什么。
-
你记录下你所做的一切。
-
你黑了无线路由器安装 Linux 软件。
-
你会发现计算机比大多数人更容易交流。
-
你懂
:(){ :|:
&
}
;:
-
你觉得命令行好玩。
-
你喜欢完全掌控一切。
-
你是根。
-
当应用于软件时,你会理解“像啤酒一样免费”和“像演讲一样免费”的区别。
-
您在机架 Shell 中安装了一台计算机。
-
您已经用散热更好的风扇替换了标准的 CPU 冷却风扇。
-
你购买零件,自己组装电脑。
-
你用液体冷却你的 CPU。
-
你可以在任何东西上安装 Linux。
-
您的电视机上连接了一个树莓派。
-
你用树莓派作为家庭网络的防火墙。
-
您运行自己的电子邮件、DHCP、NTP、NFS、DNS 和/或 SSH 服务器。
-
你入侵了你的家用电脑,用一个更快的处理器来替换它。
-
您已经升级了计算机中的 BIOS。
-
因为经常更换组件,所以您没有盖上电脑的盖子。
-
您的 ISP 提供的路由器处于“通过”模式。
-
你用 Linux 电脑当路由器。
-
…等等…
你明白了。我可以列出更多能让你成为系统管理员的东西,但是会有上百条。我相信你能想出更多适合你的。
哲学的结构
对于系统管理员来说,Linux 哲学有三个层次,类似于马斯洛的需求层次。这些层次也象征着我们通过逐渐更高层次的开悟而成长。
底层是基础——我们作为系统管理员需要知道的基本命令和知识,以便执行最底层的工作。中间层由那些建立在基础之上的实用原则组成,并告知系统管理员的日常任务。顶层包含满足我们作为系统管理员的更高需求的原则,它鼓励并使我们能够分享我们的知识。
本书分为三个部分,分别对应于图 1-1 所示的哲学层次。在哲学的第一层也是最基本的一层,奠定了基础。我们将了解“Linux 真相”、数据流、标准 IO (STDIO)、转换数据流以及“一切都是文件”的含义随着我们的工作生活开始有所启发,我们发现自己正在学习许多新的命令,如何在简单的命令行程序中有效地使用它们,以及如何利用一切都是文件的事实。这是我们哲学的基础层,在本书的第二部分有所探讨。
图 1-1
面向系统管理员的 Linux 理念的层次结构
然后,我们的旅程超越了简单地在键盘上敲击命令,我们开始探索中间层,哲学的功能方面成为我们的指南。为了更好地利用命令行,我们开始扩展我们的命令行程序来创建经过测试和可维护的 shell 程序,我们保存这些程序并可以重复使用,甚至共享。我们变成了“懒惰的管理员”,开始自动化一切。我们适当地使用 Linux 文件系统层次结构,并以开放格式存储数据。哲学的功能部分可以在第三部分找到。
在哲学的顶层,我们进入启蒙阶段,这将在第四部分讨论。随着我们开始超越仅仅执行我们的系统管理员任务和仅仅完成工作,我们对 Linux 设计中的优雅和简单的理解是完美的。我们开始努力优雅地完成自己的工作,保持解决方案简单,简化现有的复杂解决方案,并创建可用和完整的文档。我们开始探索和实验只是为了获取新知识。在这个启蒙阶段,我们开始将我们的知识和方法传递给那些新的专业人员,并且我们积极支持我们最喜欢的开源项目。
在现实生活中,哲学的层次很少是清晰的。我们如何工作和应用哲学的原则可能会因环境、头发浓密的老板、我们的训练水平和我们目前对哲学的理解而异。
谁应该读这本书
如果你是或者想成为一名系统管理员,你应该看看这本书。如果你正在履行系统管理员的一些职责,即使这不是你的职位,你应该读这本书。如果你在德文郡工作,你应该读读这本书。如果您是一台或多台 Linux 计算机的 root 用户,您应该阅读这本书。如果你经常使用和喜欢命令行,你应该读这本书。如果你觉得命令行很好玩,很强大,你应该看看这本书。看看下图中的奶牛,她也想让你读这本书。
如果你想了解让最优秀的 Linux 系统管理员变得比普通人更强大的秘密;如果你想理解解开这些秘密的概念;如果你想成为当字节击中 CPU 冷却风扇时其他人都求助的系统管理员,那么这本书就是为你准备的。
这本书不是关于学习新的命令。相反,它是关于使用您应该已经熟悉的常见和众所周知的命令,在命令行阐明 Linux 的底层结构。想想这本书和你将在练习中使用的命令,如医生用来揭示人体内部的 X 射线、CT 扫描和 MRI。这本书将向你展示如何使用一些简单的 Linux 命令来揭示 GNU/Linux 的底层结构。
面向系统管理员的 Linux 哲学旨在揭示和说明命令行的强大功能和灵活性,以及支持这些特性的设计和使用哲学。这种对如何从 Linux 命令行中获取最多信息的理解可以帮助您成为一名更好的系统管理员。
我假设本书的读者至少有一整年的使用 Linux 命令行界面的经验,最好是使用 bash shell,但是任何 shell 都可以。您应该熟悉许多 Linux 命令。
我的期望是,您已经知道如何使用适当的命令执行大部分系统管理员的工作,并为使用适当的设备进行调整。例如,当我告诉您“在/mnt 上挂载 USB 设备”时,您将明白我的意思,并能够确定要挂载哪个设备文件,使用 mount 命令执行挂载,并根据需要访问已挂载的设备以创建或查看内容。
您还应该在一台或多台 Linux 计算机上拥有 root 访问权限,并且至少已经执行了六个月的系统管理员职责。如果你已经在家里的一台或多台电脑上安装了 Linux,你就符合这个要求,应该读这本书。
但是我不符合那些要求
也许你不符合任何先前陈述的要求,但无论如何都想读这本书。无论你是想成为一名系统管理员,还是仅仅因为你认为这可能很有趣,如果你还想读这本书,那么就去读吧。
如果你对学习面向系统管理员的 Linux 哲学感兴趣,不管我上面说了什么,你都想继续读这本书,那么,就这么做吧。在这种情况下,我已经试图提供足够的信息,使你有可能进行这些实验的大部分。如果您确实遇到了问题,请联系您当地的 Linux 用户组。世界上有很多这样的组织,我发现这些组织的成员往往非常乐于助人。
如果您有兴趣学习更多关于使用 Linux 命令行和学习系统管理技巧的知识,我推荐三本书。当你进行本书中的实验时,它们会成为很好的参考。
-
Pro Linux 系统管理;马托克、丹尼斯、特恩布尔、詹姆斯、利弗丁克、彼得;压力;国际标准书号 978-1-4842-2008-5
-
开始 Linux 命令行;范·武格特,桑德;压力;国际标准书号 978-1-4302-6829-1
-
Linux 命令、编辑器和 Shell 编程实用指南第三版;索贝尔,普伦蒂斯霍尔;国际标准书号 978-0-13-308504-4
这三本书应该让您开始使用 Linux 命令行,并帮助您学习系统管理。但是最好的方法是尽可能多地亲自动手。
谁不应该读这本书
如果你只是想使用你的网络浏览器,发送电子邮件,也许使用 LibréOffice Writer 程序创建一些文档,如果你不关心 Linux 幕后发生的事情,如果你依赖别人来解决你的计算机问题,这本书不适合你。不读了。
如果你的唯一目的是想了解高级命令以及如何使用它们——这本身就是一个令人钦佩的目标——这本书不适合你。
Linux 真相
最初引用 Unix 的下面这段话暗示了 Linux 命令行的惊人威力。它也适用于 Linux。
Unix 并不是为了阻止用户做蠢事而设计的,因为那也会阻止他们做聪明的事情。
——道格·怀特
这句话总结了 Unix 和 Linux 压倒一切的真理——操作系统必须信任用户。只有通过扩展这种完全的信任度,用户才能获得操作系统的全部能力。这个真理适用于 Linux,因为它是 Unix 的直接后代。
限制性操作系统
保护用户不受其拥有的能力影响的操作系统是从这样一个基本假设开始开发的,即用户不够聪明或知识不足以信任计算机实际上可以提供的全部能力。这些操作系统是限制性的,并且具有用户界面——命令行和图形界面——这些界面通过设计强制执行这些限制。这些限制性的用户界面迫使普通用户和系统管理员等进入一个没有窗户的封闭房间,然后把门砰地关上并上三道锁。那个锁着的房间阻止他们做葛温先生提到的任何聪明的事情。
这种限制性操作系统的命令行界面提供了相对较少的命令,对任何人可能参与的可能活动提供了事实上的限制。一些用户觉得这是一种安慰。从你正在读这本书的事实来判断,我不知道,显然你也不知道。
Linux 是开放和免费的
从某种意义上说,Linux 从一开始就被设计成开放和免费的,用户和系统管理员应该在他们自己的领域内对操作系统的所有方面拥有完全的访问权。结果是我们可以用 Linux 做那些非常聪明的事情。开放和免费还有其他含义,如免费 Libré开源软件(FLOSS)和免费啤酒,但这种讨论是其他书籍的问题。
即使是最有经验的用户也可以使用 Linux 做“蠢事”。我的经验是,通过开放操作系统的全部功能,从我自己并非罕见的愚蠢中恢复变得容易得多。我发现大多数时候几个命令就可以解决问题,甚至不需要重启。有几次,我不得不切换到较低的运行级别来解决问题。我只是很少需要启动到恢复模式来编辑一个配置文件,我设法破坏得如此严重,它导致了严重的问题,包括无法启动。需要了解 Linux 的基本原理、结构和技术,才能完全释放它的力量,尤其是当东西坏了的时候。Linux 只需要系统管理员的一点理解和知识就可以完全释放它的潜力。
真正的知识
任何人都可以记忆或学习命令和程序,但死记硬背不是真正的知识。如果不了解这一理念以及它是如何体现在 Linux 的优雅结构和实现中的,就不可能将正确的命令作为工具来解决复杂的问题。我见过那些对 Linux 有着丰富知识的聪明人无法解决一个相对简单的问题,因为他们没有意识到表面之下结构的优雅。
作为一名系统管理员,在我的许多工作中,我的部分职责是协助招聘新员工。我参加了许多人的技术面试,这些人已经通过了许多微软认证,他们的简历都很好。我也参加了许多面试,在这些面试中,我们寻找 Linux 技能,但是这些申请者中很少有人有证书。当时微软认证是件大事,但在数据中心使用 Linux 的早期,很少有申请人获得认证。
我们通常以旨在确定申请人知识范围的问题开始这些面试。然后,我们将进入更有趣的问题,这些问题将测试他们通过问题找到解决方案的推理能力。我注意到一些非常有趣的结果。很少有 Windows 证书所有者能够通过我们给出的场景进行推理,而很大一部分 Linux 申请人能够这样做。
我认为这一结果部分是由于获得 Windows 证书依赖于记忆而不是实际的动手经验,以及 Windows 是一个封闭的系统,这使得系统管理员无法真正了解它是如何工作的。我认为 Linux 申请人做得更好,因为 Linux 在多个层面上是开放的,逻辑和理性可以用来识别和解决任何问题。任何使用 Linux 一段时间的系统管理员都必须了解 Linux 的架构,并且在应用知识、逻辑和推理来解决问题方面有相当丰富的经验。
启迪
这本书的大部分内容都发生在 Linux 命令行上,但它不是关于命令本身。在本书中,命令是工具,如果你知道如何照亮它,Linux 的底层结构之美就会通过它们而闪耀。这本书将通过向你展示如何使用这些常见的命令来探索这种美,从而帮助你获得启迪。
除了本书中出现的一两个命令之外,您应该已经熟悉了所有的命令。这本书将使您能够使用那些常见的命令来探索 Linux 的底层,并自己发现 Linux 的真相。
别忘了——这应该会很有趣!
https://en.wikipedia.org/wiki/Unix
2
https://en.wikipedia.org/wiki/Ken_Thompson
3
https://en.wikipedia.org/wiki/Dennis_Ritchie
4
Mike Gancarz, Linux 和 Unix 哲学,数字出版社——爱思唯尔科学出版社,2003 年,ISBN 1-55558-273-7
5
Eric S. Raymond,Unix 编程的艺术,Addison-Wesley,2003 年 9 月 17 日,ISBN 0-13-142901-9
6
Eric S. Raymond,《Unix 编程的艺术》, http://www.catb.org/esr/writings/taoup/html/
7
https://en.wikipedia.org/wiki/System_administrator
8
慈善,“Ops:现在是每个人的工作”, https://opensource.com/article/17/7/state-systems-administration
9
维基百科,“马斯洛需求层次理论”, https://en.wikipedia.org/wiki/Maslow's_hierarchy_of_needs
**
二、做好准备
这本书定义了一种哲学,但它也旨在用你可以进行的实验来阐明这种哲学的实际方面。因为我们系统管理员是一群亲自动手的人,所以这本书提供了一些简单的实验,你可以通过这些实验来更全面地欣赏和理解哲学的原则。大多数实验通常由一行 bash shell 命令或程序组成。有些实验确实使用了不止一条线。
这一章将会告诉你更多关于实验的期待。它将描述适用于这些实验的 Linux 计算机的最佳配置,并且它将为您提供一个准备在一些实验中使用的 USB 拇指驱动器的机会。
实验
作为一名动手的系统管理员,我喜欢尝试命令行,以便学习新的命令和执行任务的新方法。我为这本书设计的大部分实验都是我在自己的探索中完成的,可能做了一些小的改动以适应它们在这里的使用。
请注意,有些原则不适合实验;因此,不是你在本书中读到的每一个原则都会用实验来说明,但是尽可能多的人会做实验。许多实验说明了更多的原理,而不仅仅是它们出现的原理。
所有的系统管理员都是亲力亲为的人,尽管我们有不同的学习方式。我认为对系统管理员来说,拥有这些原则的实践经验是很有帮助的,这样才能充分想象和欣赏它们所体现的真理。这就是实验的目的——提供一个超越理论并以实际方式应用原则的机会。尽管有些实验是为了说明某一点而做的,但它们仍然是有效的。
这些启发性的实验并没有藏在每一章或每本书的结尾,在那里它们很容易被忽略——它们嵌入在文本中,是这本书流程中不可或缺的一部分。我建议你在阅读这本书时进行实验。
每个实验的命令和结果会出现在“实验”部分,如下所示。许多实验只需要一个命令,因此只有一个“实验”部分。其他的实验可能更复杂,因此分成两个或更多的实验部分。
实验示例
这是一个实验的例子。每个实验都有说明和代码,让你在电脑上输入。
许多实验会有一系列像这一段这样的散文格式的说明。只要按照说明做,实验就会顺利进行。
-
有些实验会有一系列要执行的步骤。
-
第二步。
-
等等…
Code that you are to enter for the experiments will look like this.
实验到此结束。
这些实验中的大部分都可以作为非 root 用户来执行;这比以 root 用户身份做任何事情都要安全得多。但是,对于其中一些实验,您需要成为 root 用户。
这些实验被认为在指定用于培训的计算机或虚拟机上使用是安全的。不管它们看起来有多好,您都不应该在生产系统上执行这些实验。
警告!
这些实验不应该使用生产计算机。您应该使用专门用于培训的计算机或虚拟机。
有时候,我想展示一些有趣的代码,但是你不应该在实验中运行这些代码。对于这种情况,我会将代码和任何支持文本放在如下所示的代码示例部分中。
代码示例
旨在说明某一点但你甚至不应该考虑在任何计算机上运行的代码将包含在这样的一个部分中。
echo "This is sample code which you should never run."
系统需求
你需要一台安装了 Linux 的计算机来进行这些实验。这台计算机的规格相对不重要,因为即使最小的 Linux 计算机也提供终端模拟器或控制台会话来访问命令行。为了获得最佳效果,您可以考虑的最低配置是英特尔或 AMD 硬件,至少 2GB 内存和 i3 处理器或同等配置。必要时,安装了最新版 Raspbian 的树莓派 3B 也能派上用场。
你在本书中用于实验的计算机应该是最新的主流版本,比如 Fedora、Ubuntu、Mint、RHEL 或 CentOS。无论您使用哪个发行版,都应该安装了 GUI 桌面并可供使用。一些实验需要在桌面上打开多个终端仿真会话。
你还需要一个 USB 拇指驱动器,在上面进行一些更危险的实验,包括读写硬盘上的数据。USB 拇指驱动器是一个合适的替代品,其工作方式与真正的硬盘驱动器完全相同,硬盘驱动器有旋转的磁盘和移动的磁头等。
我强烈建议您使用一台没有用于任何其他用途的主机,例如一个专门用于培训的系统,或者一台运行在 VirtualBox 等免费开源软件上的虚拟机来安装 Linux 并执行这些实验。这将大大降低生产计算机受损的可能性。
您应该对用于这些实验的计算机或虚拟机拥有 root 访问权限。如果您在任何计算机上都没有 root 用户,您将无法执行其中的一些实验。需要 root 访问权限的实验会通知您。
您应该使用一个帐户,如“学生”帐户来尝试这些实验中的大部分。这进一步降低了损坏您自己的文件的危险。事实上,大多数实验都假设您以非特权用户 student 的身份登录。
警告!
不要在生产系统上进行本书中介绍的实验。
如何访问命令行
所有现代主流 Linux 发行版都至少提供了三种访问命令行的方式。
如果您使用图形桌面,大多数发行版都有多个终端模拟器可供选择。我更喜欢 Krusader 和 Tilix,但是你可以使用任何你喜欢的终端模拟器。
Linux 还为多个虚拟控制台提供了功能,允许从一个键盘和显示器进行多次登录。虚拟控制台可以在没有 GUI 桌面的系统上使用,但也可以在有 GUI 桌面的系统上使用。
每个虚拟控制台被分配给对应于控制台编号的功能键。因此 vc1 将被分配给功能键 F1,依此类推。在这些会话之间切换很容易。在您的计算机上,您可以按住 Ctrl 和 Alt 键并按 F2 切换到 vc2。然后按住 Ctrl 和 Alt 键,按 F1 切换到 vc1 和图形界面。
在 Linux 计算机上访问命令行的最后一种方法是通过远程登录。安全 Shell(SSH)是最常见的远程访问方法。
如果您可以本地访问的计算机不适合运行这些实验,但是您可以访问远程计算机,也就是说,您可以 SSH 到该计算机来运行实验。对于某些实验,您需要多次登录。
我们将在第七章中详细介绍终端模拟器和控制台会话。
创建学生用户
作为 root 用户,您应该立即在您将用于这些实验的计算机上创建一个新用户,用户 ID 为“student”,不带引号。将密码设置为您能记住的任何合理安全的值。
制备 2-1
输入以下命令创建学生用户并分配密码。
[root@testvm1 ~]# useradd -c "Student User" student
[root@testvm1 ~]# passwd student
Changing password for user student.
New password: <Enter password>
Retype new password: <Enter password again>
passwd: all authentication tokens updated successfully.
准备 USB 拇指驱动器
你可以用一个没有其他用途的 u 盘安全地进行许多实验。当然,您将不得不在其上重新创建分区和文件系统,以便在我们完成时它可以再次使用。
我发现了一个旧的 USB 2.0 64MB 是的 MB-拇指驱动器,我目前没有其他用途,所以我设置它用于这些实验。你可以使用手头上任何大小的 u 盘,但是小的也可以。
准备 2-2
准备用于这些实验的 USB 设备。
-
在您将用于本实验的计算机上打开一个终端会话,并以 root 用户身份登录。
-
将 USB 设备插入 Linux 计算机上的 USB 插槽。
-
使用 dmesg 命令确定内核将哪个设备文件分配给了 USB 驱动器。可能会是/dev/sdb 之类的。dmesg 输出应该显示至少一个分区/dev/sdb1。在您的 Linux 计算机上,驱动器盘符(在本例中为 b)可能是不同的盘符。
警告如果在命令中指定了错误的设备,以下步骤可能会导致生产系统上的数据完全销毁。确保使用非生产系统进行此实验。
-
在/mnt 上挂载驱动器的分区。
-
将 PWD 更改为/mnt。
-
删除任何先前存在的文件。
-
输入并运行以下命令,在驱动器上创建一些包含内容的文件。
for I in 0 1 2 3 4 5 6 7 8 9 ; do dmesg > file$I.txt;done
-
验证驱动器上现在至少有 10 个名为 file0.txt 到 file9.txt 的文件。
-
将 PWD 更改为 root 的主目录。
-
卸载 USB 驱动器,并将其从计算机中移除,直到需要它为止。
USB 驱动器现在可以在我们的实验中使用了。
如果实验不成功该怎么办
这些实验是独立的,不依赖于任何设置,除了 USB 拇指驱动器或之前进行的实验的结果。某些 Linux 实用程序和工具必须存在,但这些都应该在标准 Fedora Linux 工作站安装或任何其他主流通用发行版中可用。
因此,所有这些实验都应该“正常工作”我们都知道那是怎么回事,对吧?因此,当某件事情失败时,首先要做的事情是显而易见的。
-
验证命令输入是否正确。这是我自己遇到的最常见的问题。
-
您可能会看到一条错误消息,指示找不到该命令。bash shell 显示了错误的命令;在这种情况下,我编造了 badcommand。然后给出了问题的简要描述。对于缺失和拼写错误的命令,都会显示此错误消息。多次检查命令的拼写和语法,以验证它是否正确。
[student@testvm1 ~]$ badcommand bash: badcommand: command not found...
-
使用 man 命令查看手册页(手册页),以验证命令的语法和拼写是否正确。
-
确保实际上安装了所需的命令。如果尚未安装,请安装它们。
-
对于要求您以 root 身份登录的实验,请确保您已经这样做了。应该只有几个,但是作为非根用户执行它们是不行的。
应该不会有太多其他问题——但是如果你遇到一个你无法用这些技巧解决的问题,请通过LinuxGeek46@both.org
联系我,我会尽力帮助你解决问题。
三、数据流
Linux 中的一切都围绕着数据流——尤其是文本流。
我最近在谷歌上搜索了“数据流”,大多数热门搜索都与处理单个实体中的大量流数据有关,如流视频和音频,或者金融机构处理由大量单个交易组成的流。这不是我们在这里讨论的内容,尽管概念是相同的,并且可以认为当前的应用使用 Linux 的流处理功能作为处理多种类型数据的模型。
在 Unix 和 Linux 世界中,流是源自某个源的流动文本数据;该流可以流向一个或多个程序,这些程序以某种方式对其进行转换,然后它可以存储在文件中或在终端会话中显示。作为系统管理员,您的工作与操纵这些数据流的创建和流动密切相关。在本章中,我们将探索数据流——什么是数据流,如何创建数据流,以及如何使用数据流。
文本流——通用界面
使用标准输入/输出(STDIO)进行程序输入和输出是 Linux 做事方式的关键基础。STDIO 最初是为 Unix 开发的,从那以后,它已经进入了大多数其他操作系统,包括 DOS、Windows 和 Linux。
这就是 Unix 哲学 :编写做一件事并把它做好的程序。写程序一起工作。写程序处理 文本流 ,因为那是通用接口。
—道格·麦克洛伊,Unix 基础知识 哲学 1,2
STDIO 由 Ken Thompson 3 开发,作为在早期版本的 Unix 上实现管道所需的基础设施的一部分。实现 STDIO 的程序使用标准化的文件句柄进行输入和输出,而不是存储在磁盘或其他记录媒体上的文件。STDIO 最好被描述为缓冲数据流,它的主要功能是将数据从一个程序、文件或设备的输出传输到另一个程序、文件或设备的输入。
STDIO 文件句柄
有三种 STDIO 数据流,每一种都在程序启动时作为一个文件自动打开——当然还有那些使用 STDIO 的程序。每个 STDIO 数据流都与一个文件句柄相关联,该文件句柄只是一组描述文件属性的元数据。文件句柄 0、1 和 2 被约定和长期实践分别明确定义为 STDIN、STDOUT 和 STDERR。
STDIN ,文件句柄 0,是通常从键盘输入的标准输入。STDIN 可以从任何文件重定向,包括设备文件,而不是键盘。与 STDOUT 或 STDERR 相比,重定向 STDIN 不太常见,但也可以很容易地完成。
STDOUT ,文件句柄 1,默认情况下是将数据流发送到显示器的标准输出。通常将 STDOUT 重定向到一个文件,或者通过管道将其传送到另一个程序进行进一步处理。
STDERR 与文件句柄 2 相关联。STDERR 的数据流通常也发送到显示器。
如果 STDOUT 被重定向到一个文件,STDERR 将继续显示在屏幕上。这确保了当数据流本身不在终端上显示时,STDERR 会显示出来,从而确保用户可以看到程序执行过程中产生的任何错误。STDERR 也可以重定向到同一个转换程序,或者传递到管道中的下一个转换程序。
STDIO 是作为 C 库 stdio.h 实现的,它可以包含在程序的源代码中,以便可以编译成最终的可执行文件。
生成数据流
大多数核心实用程序使用 STDIO 作为它们的输出流,而那些生成数据流的实用程序可以用来创建我们将在实验中使用的数据流,而不是以某种方式转换数据流。数据流可以短至一行甚至一个字符,也可以根据需要而定。 4
让我们尝试第一个实验,创建一个短数据流。
实验 3-1
如果您还没有这样做,请以用户“学生”的身份登录到您用于这些实验的主机如果您已经登录到 GUI 桌面会话,请启动您最喜欢的终端模拟器;如果您已经登录到一个虚拟控制台或终端模拟器,您就可以开始了。
使用下面显示的命令生成数据流。该命令以粗体显示。
[student@f26vm ~]$ ls -la
total 28
drwx------ 3 student student 4096 Oct 20 01:25 .
drwxr-xr-x. 10 root root 4096 Sep 21 10:06 ..
-rw------- 1 student student 1218 Oct 20 20:26 .bash_history
-rw-r--r-- 1 student student 18 Jun 30 11:57 .bash_logout
-rw-r--r-- 1 student student 193 Jun 30 11:57 .bash_profile
-rw-r--r-- 1 student student 231 Jun 30 11:57 .bashrc
drwxr-xr-x 4 student student 4096 Jul 5 18:00 .mozilla
该命令的输出是一个短数据流,显示在 STDOUT(您登录的控制台或终端会话)上。
在第四章“转换数据流”中,我们将把像这样的 STDOUT 数据流通过管道传输到一些 transformer 程序的 STDIN,以便对流中的数据执行一些操作。目前,我们只是在生成数据流。
一些 GNU 核心工具是专门为产生数据流而设计的。
实验 3-2
yes
命令产生一个连续的数据流,该数据流由作为参数提供的数据串的重复组成。生成的数据流将继续,直到被 Ctrl-C 中断,在屏幕上显示为^C.
输入如图所示的命令,并让它运行几秒钟。当你厌倦了看着同一串数据滚动时,按 Ctrl-C。
[student@f26vm ~]$ yes 123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
123465789-abcdefg
1234^C
“这证明了什么?,“你问吧。只是有许多方法可以创建有用的数据流。例如,您可能希望自动响应来自fsck
程序的似乎无休止的“y”输入请求,以修复硬盘上的问题。这种解决方案可以节省很多按“y”键的次数。
实验 3-3
要查看yes
如何生成一串“y”字符,再次尝试没有字符串参数的yes
命令,如实验 3-2,您将得到一串“y”字符作为输出。
[student@f26vm ~]$ yes
y
y
y
y
y
y
y
^C
现在,这是你绝对不应该尝试的事情。当以 root 用户身份运行时,rm *
命令将删除当前工作目录(pwd)中的每个文件,但它会要求您为每个文件输入“y”以确认您确实想要删除该文件。这意味着更多的打字。
代码示例 3-1
我还没有谈到管道,但是作为一名系统管理员,或者想成为一名系统管理员的人,你应该已经知道如何使用它们了。下面的 CLI 程序将对 rm 命令的每个请求提供“y”响应,并将删除所有文件。
yes | rm *
**警告!**不要运行这个命令,因为它会删除当前工作目录中的所有文件。
当然,您也可以使用rm -f *
,这也将强制删除 PWD 中的所有文件。f 表示“强制”删除。这也是你不应该做的事情。
用“是”来检验一个理论
使用 yes 命令的另一个选项是用一个包含一些任意的和非常不相关的数据的文件来填充目录,以便——嗯——填满目录。我已经使用这种技术测试了当一个特定的目录变满时,Linux 主机会发生什么。在我使用这种技术的具体例子中,我正在测试一个理论,因为一个客户遇到了问题,无法登录到他们的计算机。
注意
在这一系列实验中,我假设 USB 驱动器在/dev/sdb 上,其分区是/dev/SD B1——因为它在我的虚拟机上——确保您验证了它在您的计算机上分配的设备,因为它可能会有所不同。根据您的情况使用正确的设备文件 5 。
实验 3-4
这个实验应该以 root 用户身份进行。
为了防止填满您的根文件系统,这个实验将使用您应该提前准备好的 USB 设备。该实验不会影响设备上的现有文件。
你确实准备了那个 u 盘,不是吗?如果没有,那么现在就回到第一章。我会等…
准备好了吗?太好了!
-
现在将 USB 驱动器插入计算机上的一个 USB 插槽中。
-
使用
dmesg
命令查看 USB 驱动器的信息,并确定其分配的设备文件。应该是/dev/sdb 之类的。确保为您的设备使用正确的设备文件。 -
在我的系统上的/mnt 上挂载 USB 设备文件系统分区/dev/sdb1。
-
运行下面粗体显示的命令。由于页面宽度有限,这里显示的一些结果已经换行,但是您已经了解了。
根据你的 USB 文件系统的大小,填充它的时间可能会有所不同,但是应该会很快。
[root@testvm1 ~]# yes 123456789-abcdefgh >> /mnt/testfile.txt
yes: standard output: No space left on device
[root@testvm1 ~]# df -h /mnt
Filesystem Size Used Avail Use% Mounted on
/dev/sdb1 62M 62M 2.0K 100% /mnt
[root@testvm1 ~]# ls -l /mnt
total 62832
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file0.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file1.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file2.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file3.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file4.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file5.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file6.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file7.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file8.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file9.txt
-rwxr-xr-x 1 root root 63950848 Dec 7 13:16 testfile.txt
你的结果看起来会有些不同,但肯定会和我的相似。
请务必查看从df
输出指向/dev/sdb1 设备的那一行。这表明该文件系统上 100%的空间都被使用了。
现在从/mnt 中删除 testfile.txt 并卸载该文件系统。
作为测试的一部分,我在自己的一台计算机的/tmp 目录下使用了实验 3-4 中的简单测试来帮助我确定客户的问题。在/tmp 填满之后,用户不再能够登录 GUI 桌面,但是他们仍然可以使用控制台登录。这是因为登录 GUI 桌面会在/tmp 目录中创建文件,并且没有剩余空间,所以登录失败。控制台登录没有在/tmp 中创建新文件,因此它们成功了。我的客户没有尝试登录控制台,因为他们不熟悉 CLI。
在我自己的系统上进行验证之后,我使用控制台登录到客户主机,发现许多大文件占据了/tmp 目录中的所有空间。我删除了这些文件,并帮助客户确定文件是如何创建的,我们能够阻止这种情况。
探索 USB 驱动器
现在是做一些探索的时候了,为了尽可能的安全,您将使用您之前准备的 USB 拇指驱动器。在这个实验中,我们将研究一些文件系统结构。
先说简单的。您至少应该对dd
命令有所了解。正式名称是“磁盘转储”,许多系统管理员称之为“磁盘破坏者”是有道理的。我们中的许多人都曾使用dd
命令无意中破坏了整个硬盘或分区的内容。这就是为什么我们将使用 USB 驱动器来执行这些实验。
dd
命令是一个强大的工具,它允许我们使用任何文件或设备生成数据流,如硬盘驱动器、磁盘分区、RAM 内存、虚拟控制台、终端仿真会话、STDIO 等等,作为源和目标。因为dd
命令不修改这些数据流,所以它允许我们访问原始数据,这样我们就可以查看和分析它。
随着我们在这一系列实验中的进展,你会看到由dd
生成的数据流可以用于许多不同的目的。这是我最喜欢的探索文件和设备的工具之一。
实验 3-5
本实验不需要安装 USB 驱动器;事实上,如果不安装设备,这个实验会给人留下更深刻的印象。如果 USB 设备当前已安装,请将其卸载。
以 root 用户身份登录到终端会话。
作为终端会话中的 root 用户,使用 dd 命令查看 USB 驱动器的引导记录,假设它被分配给/dev/sdb 设备。bs=参数不是您可能会想到的;它只是指定块大小,count=参数指定转储到 STDIO 的块数。of=参数指定数据流的来源,在本例中是 USB 设备。
[root@f26vm ~]# dd if=/dev/sdb bs=512 count=1
•>•MSWIN4.1P•} •••)L•0NO NAME FAT16 •}•3•••{••x•vVU•"•~•N•
•••|•E••F•E••8f$|•r<•F••fFVF•PR•F•V•• •v••^
•H••F•N•ZX••••rG8-t•
V•v>•^tJNt
••F•V••S••[r•?MZu•••BJu••pPRQ••3••v••vB•••v••V$•••••••t<•t •••••}•
•}••3••^••D•••}•}••r••HH•N ̸
•YZXr @uB^
•••'
Invalid system disk•
Disk I/O error•
Replace the disk,!••U•
1+0 records in
1+0 records out
512 bytes copied, 0.0116131 s, 44.1 kB/s
这将打印引导记录的文本,引导记录是磁盘上的第一个块——任何磁盘。在这种情况下,有关于文件系统和分区表的信息,尽管因为它是以二进制格式存储的,所以不可读。如果这是一个可引导设备,GRUB 的第一阶段或其他引导加载程序将位于这个扇区。我在引导记录本身后面添加了几个换行符,以便阐明扇区中数据的结尾和 dd 命令本身打印的信息。最后三行包含关于记录数和处理的字节数的数据。
现在让我们做同样的实验,但是是在第一个分区的第一条记录上。
实验 3-6
USB 设备仍应被插入和卸载,并且您仍应以 root 用户身份登录。
-
运行以下命令。
[root@f26vm ~]# dd if=/dev/sdb1 bs=512 count=1 •<•mkfs.fat•|••)•GR•NO NAME FAT16 •[|•"•t V•••^••2•••••This is not a bootable disk. Please insert a bootable floppy and press any key to try again ... U•1+0 records in 1+0 records out 512 bytes copied, 0.0113664 s, 45.0 kB/s
这个实验显示了引导记录和分区的第一个记录之间的差异。它还显示了dd
命令可以用来查看分区中的数据以及磁盘本身的数据。
让我们看看 u 盘里还有什么。根据您在这些实验中使用的 USB 设备的具体情况,您可能会得到与我不同的结果。我会告诉你我做了什么,你可以修改,如果有必要达到预期的结果。
我们正在尝试使用dd
命令来定位我们在 USB 驱动器上创建的文件的目录条目,然后是一些数据。如果我们对元数据结构有足够的了解,我们可以直接解释它们来找到这些数据在驱动器上的位置,但是我们没有,所以我们将不得不硬着头皮这样做——打印出数据,直到我们找到我们想要的。
所以,让我们从我们所知道的开始,然后用一点技巧继续。我们知道我们在 USB 设备准备期间创建的数据文件在设备的第一个分区中。因此,我们不需要搜索引导记录和第一个分区之间的空间,其中包含许多空白。至少这是它应该包含的内容。
从/dev/sdb1 的开头开始,让我们一次查看几个数据块,找到我们想要的。实验 3-7 中的命令与前一个相似,只是我们指定了更多的数据块来查看。如果您的终端不够大,无法一次显示所有数据,您可能必须指定较少的块,或者您可以通过 less 实用程序传输数据,并使用它来逐页浏览数据。两种方式都可行。请记住,我们是以 root 用户的身份执行所有这些操作的,因为非 root 用户没有所需的权限。
实验 3-7
输入与上一个实验中相同的命令,但是将显示的块数增加到 10,如下所示,以便显示更多数据。
[root@f26vm ~]# dd if=/dev/sdb1 bs=512 count=10
•<•mkfs.fat•|••)•GR•NO NAME FAT16 •[|•"•t
V•••^••2•••••This is not a bootable disk. Please insert a bootable floppy and
press any key to try again ...
U•••••
•• !"#$%&'(••*+,-./0123456789:;••=>?@ABCDEFGHIJKLMN••PQRSTUVWXYZ[\]^_`a••cdefghijklmnopqrst••vwxyz{|}~••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••10+0 records in
10+0 records out
5120 bytes (5.1 kB, 5.0 KiB) copied, 0.019035 s, 269 kB/s
这里没有太大的不同,但是让我们看得更远一点。
让我们看看dd
命令的一个新选项,它给了我们更多的灵活性。
实验 3-8
我们仍然希望一次显示大约 10 个数据块,但是我们不想从分区的开始处开始,我们希望跳过我们已经查看过的数据块。
输入以下命令并添加skip=10
参数,它会跳过前 10 个数据块并显示接下来的 10 个数据块。
[root@f26vm ~]# dd if=/dev/sdb1 bs=512 count=10 skip=10
10+0 records in
10+0 records out
5120 bytes (5.1 kB, 5.0 KiB) copied, 0.01786 s, 287 kB/s
我们在实验 3-8 中看到,分区的后 10 个块是空的;那就是。它们包含空值,不打印,因为它们是空的-什么也不是。我们可以在分区的开始处继续跳过越来越多的块,或者在计数和跳过参数中使用更大的增量,比如 20 和 20。但我希望能为你节省一些时间。我发现如果我跳过 250 个块,就会显示目录条目。如果您的 USB 驱动器大小不同或格式不同,这可能不适合您,但这应该是一个好的起点。
实验 3-9
现在输入 dd 命令,跳过 250 块。
[root@f26vm ~]# dd if=/dev/sdb1 bs=512 count=10 skip=250
Afile0•.txt••••••FILE0 TXT •jgKgK•jgK••Afile1•.txt••••••FILE1TXT
•jgKgK•jgK••Afile2•.txt••••••FILE2 TXT •jgKgK•jgK)••Afile3•.txt••••••FILE3 TXT •jgKgK•jgK<••Afile4•.txt••••••FILE4 TXT •jgKgK•jgKO••Afile5•.txt••••••FILE5 TXT •jgKgK•jgKb••Afile6A.txt••••••FILE6 TXT •jgKgK•jgKu••Afile7E.txt••••••FILE7 TXT •jgKgK•jgK•••Afile8•.txt••••••FILE8 TXT •jgKgK•jgK•••Afile9M.txt••••••FILE9 TXT •jgKgK•jgK•••10+0 records in
10+0 records out
5120 bytes (5.1 kB, 5.0 KiB) copied, 0.0165904 s, 309 kB/s
如果您在第一次尝试时没有看到类似于上面所示的目录,请尝试更改要跳过的块数,然后再次运行该实验。我们的技术审查人员确实找到了目录,但使用了非常不同的跳过计数。
该命令的输出显示了/dev/sdb1 分区目录中包含的数据。这表明目录只是分区上的数据,就像任何其他数据一样。
我还发现跳过 500 个块会显示其中一个文件的数据,如下面的实验 3-10 所示。
实验 3-10
这次输入dd
命令,跳过计数为 5 的 500 个块,只显示 5 个块。注意,这些结果是换行的,但是dmesg
中的每一行都以时间戳开始。
[root@f26vm ~]# dd if=/dev/sdb1 bs=512 count=5 skip=500
msg='unit=systemd-journald comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 6.430317] audit: type=1131 audit(1509824958.916:49): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-journald comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 6.517686] audit: type=1305 audit(1509824959.007:50): audit_enabled=1 old=1 auid=4294967295 ses=4294967295 res=1
[ 6.665314] audit: type=1130 audit(1509824959.154:51): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-journald comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 6.671171] audit: type=1130 audit(1509824959.160:52): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=kmod-static-nodes comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 6.755493] audit: type=1130 audit(1509824959.244:53): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-sysctl comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 9.782860] RAPL PMU: hw unit of domain pp0-core 2^-0 Joules
[ 9.783651] RAPL PMU: hw unit of domain package 2^-0 Joules
[ 9.784427] RAPL PMU: hw unit of domain pp1-gpu 2^-0 Joules
[ 9.785611] ppdev: user-space parallel port driver
[ 9.948408] Adding 4177916k swap on /dev/mapper/fedora_f26vm-swap. Priority:-1 extents:1 across:4177916k FS
[ 10.082485] snd_intel8x0 0000:00:05.0: white list rate for 1028:0177 is 48000
[ 10.441113] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
[ 11.456654] kauditd_printk_skb: 15 callbacks suppressed
[ 11.457548] audit: type=1130 audit(1509824963.942:69): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=lvm2-pvscan@8:2 comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[ 11.523286] audit: type=1130 audit(1509824964.012:70): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-fsck@dev-mapper-fedora_f26vm\x2dhome co5+0 records in
5+0 records out
2560 bytes (2.6 kB, 2.5 KiB) copied, 0.0223881 s, 114 kB/s
我不知道数据来自哪个文件。如果我们真的想的话,我们可以算出来,但是这对于本书的目的来说是不必要的。请注意,在您的驱动器上,目录和文件本身的位置可能不同。你可能需要搜索一下才能找到它们,但这是它们在我的设备上的位置。
你绝对应该花些时间自己探索一下 u 盘的内容。你可能会对你的发现感到惊讶。
一连串的随机性
事实证明,随机性在计算机中是一种可取的东西。谁知道呢。系统管理员想要生成随机数据流的原因有很多。从其他来源(如文件或硬盘分区等设备)生成的数据流应该包含非随机数据,这些数据可能会被黑帽黑客用来获取私人或机密数据。使用保证是随机的数据流提供了一个更安全的选择。
随机数据流有时有助于覆盖整个分区的内容,例如/dev/sda1,甚至是/dev/sda 中的整个硬盘驱动器。
尽管删除文件似乎是永久性的,但事实并非如此。许多取证工具是可用的,并且可以被训练有素的取证专家用来容易地恢复假定已经被删除的文件。恢复被随机数据覆盖的文件要困难得多。我经常不仅需要删除硬盘上的所有数据,还需要覆盖它,使其无法恢复。我这样做是为了客户和朋友,他们把旧电脑“送给”我,让我重复使用或回收。
不管电脑最终会发生什么,我向捐赠电脑的人保证,我会清除硬盘上的所有数据。我从计算机中取出驱动器,将它们放入我的插入式硬盘驱动器扩展坞,并使用类似于实验 3-11 中的命令来覆盖所有数据,但不是像本实验中那样将随机数据输出到 STDOUT。我将其重定向到需要覆盖的硬盘驱动器的设备文件,但不要这样做。
实验 3-11
输入这个命令将无休止的随机数据流打印到 STDOUT。
[student@testvm1 ~]$ cat /dev/urandom
使用Ctrl-C
中断和停止数据流。
如果你非常偏执,可以使用shred
命令来覆盖单个文件以及分区和完整的驱动器。它可以根据需要多次覆盖设备,让您感到安全,多次使用随机数据以及专门设计的有序数据模式,以防止即使是最敏感的设备也无法从硬盘上恢复任何数据。与其他使用随机数据的实用程序一样,随机流是由/dev/urandom 设备提供的。
随机数据也用作程序的输入种子,这些程序生成用于科学和统计计算的随机密码、随机数据和数字。我将在第四章中更详细地介绍随机性和其他有趣的数据源:“一切都是一个文件。”
摘要
在本章中,您了解到 STDIO 只不过是数据流。这些数据几乎可以是任何内容,可以是列出目录中文件的命令输出,也可以是来自特殊设备(如/dev/urandom)的无休止的数据流,甚至可以是包含来自硬盘驱动器或分区的所有原始数据的数据流。您学习了一些不同且有趣的方法来生成不同类型的数据流,以及如何使用dd
命令来探索硬盘的内容。
Linux 计算机上的任何设备都可以被视为数据流。您可以使用像dd
和cat
这样的普通工具将设备中的数据转储到 STDIO 数据流中,该数据流可以使用其他普通的 Linux 工具进行处理。
到目前为止,除了查看这些数据流,我们还没有对它们做任何事情。但是等等,还有更多!请继续阅读。
Eric S. Raymond,Unix 编程的艺术, http://www.catb.org/esr/writings/taoup/html/ch01s06.html
2
Linuxtopia,Unix 哲学基础知识, http://www.linuxtopia.org/online_books/programming_books/art_of_unix_programming/ch01s06.html
3
维基百科,【肯汤普森】, https://en.wikipedia.org/wiki/Ken_Thompson
4
例如,从特殊设备文件 random、urandom 和 zero 获取的数据流可以永远继续,而无需某种形式的外部终止,例如用户输入 Ctrl-C、命令的限制参数或系统故障。
5
我们将在第五章“一切都是文件”中了解更多关于设备文件和/dev 目录的信息
四、转换数据流
本章介绍了使用管道将数据流从一个实用程序连接到另一个使用 STDIO 的实用程序。你将了解到这些程序的功能是以某种方式转换数据。您还将了解如何使用重定向将数据重定向到文件。
我将术语“transform”与这些程序结合使用,因为每个程序的主要任务是按照系统管理员的意图,以特定的方式转换来自 STDIN 的输入数据,并将转换后的数据发送到 STDOUT,以供另一个 transformer 程序使用或重定向到一个文件。
标准术语“过滤器”暗示了一些我不同意的东西。根据定义,过滤器是一种去除某些东西的装置或工具,例如空气过滤器可以去除空气中的污染物,这样汽车的内燃机就不会被这些微粒磨死。在我高中和大学的化学课上,滤纸被用来去除液体中的微粒。我家暖通空调系统中的空气过滤器去除了我不想呼吸的微粒。
虽然它们有时会从流中过滤掉不需要的数据,但我更喜欢“转换器”这个术语,因为这些实用程序做得更多。他们可以向数据流中添加数据,以一些令人惊讶的方式修改数据,对数据进行排序,重新排列每行中的数据,根据数据流的内容执行操作,等等。
随便你用哪个词,但我更喜欢变形金刚。
作为原材料的数据流
数据流是核心实用程序和许多其他 CLI 工具执行工作所依赖的原始资料。顾名思义,数据流是使用 STDIO 从一个文件、设备或程序传递到另一个文件、设备或程序的数据流。
可以通过使用管道将转换器插入数据流来操作数据流。SysAdmin 使用每个 transformer 程序对流中的数据执行一些操作,从而以某种方式改变其内容。然后可以在管道末端使用重定向将数据流定向到文件。如前所述,该文件可以是硬盘上的实际数据文件,也可以是设备文件,如驱动器分区、打印机、终端、伪终端或任何其他连接到计算机的设备。
使用这些小而强大的 transformer 程序操纵这些数据流的能力是 Linux 命令行界面的核心。许多核心实用程序都是 transformer 程序,并使用 STDIO。
白日梦
管道对于我们在命令行上做令人惊奇的事情至关重要,以至于我认为认识到它们是由道格拉斯·麦克洛伊 2 在 Unix 早期发明的是很重要的。谢谢道格。普林斯顿大学的网站上有一段对麦克洛伊的采访片段 3 ,其中他讨论了管道的创建和 Unix 哲学的开端。
请注意实验 4-1 中显示的简单命令行程序中管道的使用,该程序一次列出每个登录用户,不管他们有多少个活动登录。
实验 4-1
如果您尚未这样做,请打开一个终端会话,以学生用户身份登录,然后以 root 用户身份登录第二个终端会话。
在一行中输入如下所示的命令。
[student@testvm1 ~]$ w | tail -n +3 | awk '{print $1}' | sort | uniq
root
student
您还可以使用sort -u
来代替uniq
转换器,以确保每个登录 ID 只打印一个实例。输入下面的命令试试看。
[student@testvm1 ~]$ w | tail -n +3 | awk '{print $1}' | sort -u
root
student
这些命令的结果产生两行数据,显示用户 root 和 student 都已登录。它不显示每个用户登录的次数。
实验 4-1 中的两条命令管道产生了相同的结果。在这个实验中,至少还有一种方法可以改变命令管道,同时仍然生成相同的结果。你能找到它吗?有许多方法可以完成同样的任务。没有对错,只是不同而已。在我看来,使用第二种形式既简单又优雅。我们将在第十七章“追求优雅”和第十八章“寻找简单”中讨论这些属性。"
管道——由竖线(|)表示——是将这些命令行实用程序连接在一起的语法粘合剂、操作符。管道允许一个命令的标准输出被“管道化”,即从一个命令的标准输出流到下一个命令的标准输入。
用管道连接的一串程序被称为管道,使用 STDIO 的程序被正式称为过滤器,但我更喜欢用转换器这个术语。
想想如果我们不能将数据流从一个命令传输到下一个命令,这个程序将如何工作。第一个命令将对数据执行任务,然后该命令的输出必须保存在一个文件中。下一个命令必须从中间文件中读取数据流,并对数据流进行修改,将自己的输出发送到一个新的临时数据文件中。第三个命令将不得不从第二个临时数据文件中取出它的数据,并执行它自己的数据流操作,然后将得到的数据流存储在另一个临时文件中。在每一步,数据文件名必须以某种方式从一个命令传递到下一个命令。
我甚至无法忍受去想它,因为它太复杂了。记住简单就是摇滚!
建设管道
当我做一些新的事情,解决一个新的问题时,我通常不会像实验 4-1 那样,从头开始输入一个完整的 bash 命令管道。我通常从管道中的一两个命令开始,然后通过添加更多命令来进一步处理数据流。这允许我在管道中的每个命令之后查看数据流的状态,并在需要时进行纠正。
在实验 4-2 中,你应该输入每行显示的命令,并按所示运行它以查看结果。这将让你感受到如何分阶段构建复杂的管道。
实验 4-2
输入每行显示的命令。当使用管道将每个新的 transformer 实用程序添加到数据流中时,观察数据流中的变化。第一次通过时,使用uniq
工具。这个实验的最终结果将与实验 4-1 的结果相同。
[student@f26vm ~]$ w
[student@f26vm ~]$ w | tail -n +3
[student@f26vm ~]$ w | tail -n +3 | awk '{print $1}'
[student@f26vm ~]$ w | tail -n +3 | awk '{print $1}' | sort
[student@f26vm ~]$ w | tail -n +3 | awk '{print $1}' | sort | uniq
Now let’s also use the alternate form of this last command.
[student@f26vm ~]$ w | tail -n +3 | awk '{print $1}' | sort -n
这个实验的结果说明了由管道中的每个 transformer 实用程序执行的对数据流的改变。
可以构建非常复杂的管道,使用许多与 STDIO 一起工作的不同实用程序来转换数据流。
重寄
重定向是将程序的标准输出数据流重定向到一个文件而不是显示的默认目标的能力。“大于号”(>)字符,也称为“gt”,是重定向的语法符号。实验 4-3 展示了如何将df -h
命令的输出数据流重定向到文件 diskusage.txt。
实验 4-3
重定向命令的 STDOUT 可用于创建包含该命令结果的文件。
[student@f26vm ~]$ df -h > diskusage.txt
除非出现错误,否则该命令不会向终端输出任何内容。这是因为 STDOUT 数据流被重定向到文件,而 STDERR 仍然被定向到 STDOUT 设备,即显示器。您可以使用下面的命令查看刚刚创建的文件的内容。
[student@f26vm ~]$ cat diskusage.txt
Filesystem Size Used Avail Use% Mounted on
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 988K 2.0G 1% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/fedora_f26vm-root 49G 11G 36G 24% /
tmpfs 2.0G 0 2.0G 0% /tmp
/dev/sda1 976M 158M 752M 18% /boot
/dev/mapper/fedora_f26vm-home 25G 45M 24G 1% /home
tmpfs 396M 0 396M 0% /run/user/991
tmpfs 396M 0 396M 0% /run/user/1001
使用>符号进行重定向时,如果指定的文件尚不存在,则会创建该文件。如果它已经存在,内容将被来自命令的数据流覆盖。如实验 4-4 所示,你可以使用双大于号>>,将新的数据流附加到文件中任何现有的内容上。
实验 4-4
该命令将新数据流追加到现有文件的末尾。
[student@f26vm ~]$ df -h >> diskusage.txt
您可以使用 cat 和/或更低版本查看 diskusage.txt 文件,以验证新数据是否已附加到文件末尾。
使用重定向到标准输入的一个例子是使用od
命令,如实验 4-5 所示。N 50 选项防止输出永远持续下去。如果不使用-N 选项来限制输出数据流,可以使用 Ctrl-C 来终止它。
实验 4-5
这个实验演示了使用重定向作为 STDIN 的输入。
[student@f26vm ~]$ od -c -N 50 < /dev/urandom
0000000 331 203 _ 307 ] { 335 337 6 257 347 $ J Z U
0000020 245 \0 ` \b 8 307 261 207 K : } S \ 276 344 ;
0000040 336 256 221 317 314 241 352 ` 253 333 367 003 374 264 335 4
0000060 U \n 347 ( h 263 354 251 u H ] 315 376 W 205 \0
0000100 323 263 024 % 355 003 214 354 343 \ a 254 # ` { _
0000120 b 201 222 2 265 [ 372 215 334 253 273 250 L c 241 233
<snip>
本实验中的字体大小已经减小,因此无需换行即可适应。理解结果的本质要容易得多。
重定向可以是管道的来源,也可以是管道的终点。因为很少需要它作为输入,重定向通常被用作管道的终止。
重定向标准错误
STDERR 被设计为打印在 STDERR 设备上——通常是与 STDOUT 相同的终端会话——以确保错误消息被显示出来,并且可以被系统管理员查看,而不是通过管道传递并可能丢失。即使 STDOUT 被重定向或通过管道传送到管道的下一级,STDERR 通常也会显示在终端上。
实验 4-6 说明了 STDERR 数据流的默认行为,然后继续展示如何创建替代行为。
实验 4-6
让我们通过在您的主目录中创建一些测试文件来开始这个实验。在一行中输入以下命令。
[student@testvm1 ~]$ for I in 0 1 2 3 4 5 6 7 8 9;do echo "This is file $I" > file$I.txt;done
现在使用 cat 命令连接其中三个文件的内容。在这一点上,我们仍然不期望任何错误,只是设置阶段。
[student@testvm1 ~]$ cat file0.txt file4.txt file7.txt > test1.txt
[student@testvm1 ~]$ cat test1.txt
This is file 0
This is file 4
This is file 7
到目前为止,一切正常。现在让我们更改命令,通过指定一个不存在的文件来生成一个简单的错误。我们指定了不存在的 filex.txt,而不是 file4.txt。
[student@testvm1 ~]$ cat file0.txt filex.txt file7.txt > test1.txt
cat: filex.txt: No such file or directory
[student@testvm1 ~]$ cat test1.txt
This is file 0
This is file 7
当数据仍然被重定向到 test1.txt 时,cat 命令生成的错误消息出现在终端上。
[student@testvm1 ~]$ cat file0.txt filex.txt file7.txt &> test1.txt
[student@testvm1 ~]$ cat test1.txt
This is file 0
cat: filex.txt: No such file or directory
This is file 7
在上面的命令中,STDOUT 和 STDERR 都被重定向到文件 test1.txt。现在让我们假设我们希望 STDOUT 继续被发送到终端,而我们并不关心错误消息。为此,我们将 STDERR 重定向到/dev/null。 4 首先我们确保 test1.txt 为空,这样就不会有任何数据存储在其中而混淆结果。
[student@testvm1 ~]$ echo "" > test1.txt
[student@testvm1 ~]$ cat test1.txt
[student@testvm1 ~]$ cat file0.txt filex.txt file7.txt 2>
/dev
/
null
This is file 0
This is file 7
[student@testvm1 ~]$ cat test1.txt
[student@testvm1 ~]$
我们还可以将 STDERR 重定向到 test1.txt 文件,同时仍然将 STDOUT 发送到终端。
[student@testvm1 ~]$ cat file0.txt filex.txt file7.txt 2> test1.txt
This is file 0
This is file 7
[student@testvm1 ~]$ cat test1.txt
cat: filex.txt: No such file or directory
[student@testvm1 ~]$
我们可能还会发现将 STDOUT 重定向到一个文件并将 STDERR 重定向到另一个文件是很有用的。这看起来像下面的命令。
[student@testvm1 ~]$ cat file0.txt filex.txt file7.txt 1> good.txt 2> error.txt
[student@testvm1 ~]$ cat good.txt
This is file 0
This is file 7
[student@testvm1 ~]$ cat error.txt
cat: filex.txt: No such file or directory
[student@testvm1 ~]$
重定向提供的灵活性使我们有可能以一种非常优雅的方式执行一些令人惊奇的事情。例如,我有一些脚本会输出大量的输出,这使得很难确定是否发生了任何错误。通过将 STDOUT 重定向到一个日志文件,将 STDERR 重定向到另一个日志文件,我可以很容易地确定是否有任何错误,而不必搜索将近一兆字节的数据。
管道挑战
我为 Opensource.com5写了很多东西,几年前我向我们的读者提出了一个挑战,其中涉及到管道作为解决方案的必要组件。这是一个简单的问题,有一个我经常使用的解决方案。
问题
我有多台计算机配置为向我自己的电子邮件帐户发送管理电子邮件。我已经在我的邮件服务器上配置了 procmail,将这些管理邮件中的大部分移到一个文件夹中,这样就可以很容易地找到它们。在过去的几年里,我在那个文件夹里收集了超过 50,000 封电子邮件。这些电子邮件包括来自 rkhunter (Rootkit hunter)、logwatch、cron jobs 和 Fail2Ban 等的输出。
我感兴趣的消息来自 Fail2Ban,这是一个免费的开源软件,可以动态禁止试图恶意访问我自己主机的主机的 IP 地址,主要是互联网上的防火墙。Fail2Ban 通过向 IPTables 添加规则来做到这一点。每当一个 IP 地址因多次 SSH 登录尝试失败而被禁止时,Fail2Ban 就会发送一封电子邮件。
挑战的目标是创建一个命令行程序来计算来自每个 IP 地址的试图使用 SSH 访问我的主机的电子邮件数量。参赛者将下载 admin.index 文件,其中包含从我的电子邮件客户端导出的 CSV 数据,以及从电子邮件中提取的超过 50,000 个主题行。所有的主题行都包含在参赛者可用的数据中,因此部分任务是只提取与禁止的 SSH 连接相关的主题行。图 4-1 中显示了参赛者可用数据的一个小样本。请注意,图中有一些线条被包裹起来,但你明白了。
图 4-1
挑战中使用的 CSV 数据示例
规则规定命令行程序应该只有一行,并且必须使用管道将数据从一个命令传送到下一个命令。对于额外的学分,结果可以包括每个 IP 地址的国家的名称。
解决方案
我们收到了居住在世界各地许多国家的 Opensource.com 读者的来信。有些人提交了多个解决方案,但竞赛规则规定,只有参赛者的第一个解决方案将被考虑。因此,一些好的参赛作品不得不被取消资格,因为它们是同一个人的第二次或第三次参赛作品。
我有自己非常简单的解决方案,如图 4-2 所示。然而,即使我有资格,也不会是赢家。事实上,许多参赛作品提供了比我自己更好的解决方案。
图 4-2
我自己解决问题的方法
我自己的解决方案提供了一个按 IP 地址升序排序的列表,其中大多数条目的源数据来自 admin.index 文件。我的解决方案中的最后一种方法并不是赢得比赛的必要条件,但它是我喜欢做的事情,以查看大多数攻击是从哪里发出的。
我的解决方案产生了 5,377 行输出,所以大约有这个数量的唯一 IP 地址。然而,我的解决方案没有考虑到一些没有 IP 地址的异常条目。当我在思考命令行程序在这个挑战中的目标时,我决定不指定应该产生的行数,因为我觉得这可能限制太多,并且会对条目施加不必要的约束。我认为这是一个好主意,因为我们收到的许多条目产生了多少有些不同的数字。所以一个成功的解决方案不需要产生和我的解决方案一样多的数据行。
带解决方案的第一个条目
美国新泽西州汉密尔顿的迈克尔·迪多梅尼科提交了比赛的第一份参赛作品,这也是一份工作。我特别喜欢 Michael 使用 sort 命令来确保输出按照 IP 地址排序。
Michael 的输入,如图 4-3 所示,产生 5295 行输出,与我自己的结果相差不大。这也是许多其他条目产生的输出行数。
图 4-3
Michael DiDomenico 提交了第一个带有正确答案的条目
最短解决方案
有资格获奖的最短解决方案是由西班牙马德里的 Víctor Ochoa Rodríguez 提交的。他在图 4-4 中的 65 个字符的解决方案非常优雅,使用 egrep 仅选择包含 SSH 和 IP 地址的行,同时仅打印每行中与表达式匹配的部分。我从这个条目中了解到了-o 选项,所以感谢 Víctor 提供的这一点新知识。
图 4-4
维克多·奥乔亚·罗德里格斯提交了这个解决方案,这是有资格获奖的最短的一个
图 4-5 显示了另一个实际上比 Víctor 更短的条目。Teresa e Junior 提交了一个长度为 58 个字符的条目。她没有资格在竞赛中获奖,但她的解决方案至少应该在这个类别中得到非正式的认可。
图 4-5
小特雷莎·e·提交的这份文件是所有文件中最短的
这两种解决方案都会产生 5,295 行输出。
最有创意的解决方案
前两个类别可以根据纯粹的客观标准来判断,所以我希望有这个类别来提供一个额外的机会,以表彰那些提出更有创意的答案的人。这一类别的结果是基于我的纯主观意见,在我看来,这一类别有一个平局。
爱尔兰科克公司的 Przemo Firszt 提交了图 4-6 中的参赛作品,该作品因其对 tee 和 xargs 命令的使用而非常有趣且富有创意。它的独特之处还在于,除了使用管道之外,它还使用 tee 命令将中间数据存储在一个文件中,该命令还将数据传递给 STDOUT,最终输出被重定向到另一个文件,而不是允许输出到 STDOUT。它甚至在最后通过删除临时文件来进行清理。
图 4-6
Przemo Firszt 提交了这个使用 tee 和 xargs 的创意作品
这个解决方案产生 7,403 行输出。这似乎是因为许多 IP 地址有多行。因此,尽管这不是一个完美的解决方案,但只需很少的修改就可以为每个 IP 地址生成一行输出。
美国德克萨斯州弗里斯科的蒂姆·蔡斯。,是这个类别的另一个赢家。Tim 的条目如图 4-7 所示,其独特之处在于它使用 curl 命令从服务器下载文件,然后它使用 awk 命令选择文件中所需的行,并仅从每一行中选择 IP 地址。Tim 的解决方案是唯一包含执行文件下载的代码的解决方案。它产生 5,295 行输出。
图 4-7
Tim Chase 的解决方案在使用 curl 下载文件方面很有创意
额外积分解决方案
许多条目旨在满足额外积分解决方案的要求,为每个 IP 地址提供国家名称。我找到了两个特别引起我兴趣的条目。这两个条目都使用 GeoIP 包提供本地数据库来获取国家信息。其他几个条目使用了whois
命令,但是除了其他问题之外,whois
使用了远程数据库,当从单个 IP 地址访问太快时,就会被阻塞。GeoIP 包在标准 Fedora 存储库和 EPEL CentOS 存储库中提供。
来自阿根廷的 Gustavo Yzaguirre 提交了图 4-8 中的条目,我喜欢它,因为它首先给出了一个带有计数的 IP 地址的基本列表,然后列出了国家。它产生 16,419 行输出,其中许多是重复的。Gustavo 说它没有优化,但这不是要求之一。
图 4-8
Gustavo Yzaguirre 提交了这个条目,列出了每个 IP 地址的国家名称
塞尔维亚贝尔格莱德的 Dejan Bogdanovic 也提交了一个非常有趣的额外积分解决方案。他在图 4-9 中的条目按频率降序列出了 IP 地址和国家信息。德扬的条目产生 5,764 行输出。
图 4-9
这个额外学分条目是由德扬·波格丹诺维奇提交的
关于解决方案的思考
我很惊讶 Opensource.com 的读者能想出这么多不同的方法来解决这个问题。在某种程度上,我认为这是因为许多参与者对预期结果的解释有点随意,在许多情况下,添加了比原始规范中要求的更多的信息。
在所有的解决方案中也有很多创意。没有两个解决方案是相同的,这强调了每个人解决问题的方式不同的事实。即使有些解决方案看起来是从相同的角度出发的,但每个解决方案都有自己的个性和一点天赋,这只能是多样化、聪明、知识渊博且非常有创造力的系统管理员带来的独特视角的产物。
让我们把这个竞赛作为现实世界的一个隐喻。竞赛规则是这个项目的规范。每个系统管理员,甚至那些没有在竞赛中胜出的系统管理员,都采用了那些规范,并精心制作了满足需求的解决方案,这些解决方案也具有惊人的创造力。每个解决方案都说明了如何使用 transformer 程序和 STDIO 来转换数据流,最终为系统管理员提供有意义的信息。
这场竞赛也很好地说明了“没有应该”没有一种方法可以让你“应该”做任何事情。重要的是结果。你知道,这听起来很好,我应该把它作为信条之一。在我写作的这一点上,我还没有把它当作一个信条,但它确实是,所以我现在就要创造这一章。
摘要
对于系统管理员来说,只有使用管道和重定向,Linux 哲学的许多原则才有意义。管道将 STDIO 数据流从一个程序或文件传输到另一个程序或文件。在本章中,您已经了解到通过一个或多个 transformer 程序使用管道传输数据流支持对这些流中的数据进行强大而灵活的操作。
实验中展示的每个项目,以及这里展示的所有参赛项目,都很小,而且每个项目都做得很好。他们也是变形金刚,也就是说。它们接受标准输入,以某种方式进行处理,然后将输出发送到标准输出。将这些程序实现为转换器,将经过处理的数据流从它们自己的标准输出发送到其他程序的标准输入,这是对将管道实现为 Linux 工具的补充,也是必要的。
在 Linux 系统中,所有硬件设备都被视为文件。在第五章“一切都是一个文件”中有更多关于这个的内容
2
维基百科,道格拉斯·麦克洛伊传, http://www.cs.dartmouth.edu/~doug/biography
3
普林斯顿大学,采访道格拉斯·麦克洛伊, https://www.princeton.edu/~hos/frs122/precis/mcilroy.htm
4
我们将在第五章“一切都是文件”中学习更多关于设备特殊文件的知识,比如/dev/null
5
五、一切都是文件
这是使 Linux 特别灵活和强大的最重要的概念之一:一切都是文件。也就是说,一切都可以是数据流的源,数据流的目标,或者在许多情况下两者都是。在这一章中,你将探索“一切都是一个文件”的真正含义,并学习作为一名系统管理员如何利用它。
“一切都是一个文件”的全部意义在于……你可以使用普通的工具来操作不同的东西。
—电子邮件中的莱纳斯·托瓦尔兹
什么是文件?
这是给你的一个难题。下列哪些是文件?
-
目录
-
Shell 脚本
-
运行终端模拟器
-
文档库
-
串行端口
-
内核数据结构
-
内核调整参数
-
硬盘-/开发/sda
-
/dev/null
-
分区- /dev/sda1
-
逻辑卷(LVM)-/开发/映射器/卷 1-tmp
-
打印机
-
套接字
对 Unix 和 Linux 来说,它们都是文件,这是计算史上最惊人的概念之一。它使一些非常简单但功能强大的方法成为可能,这些方法用于执行许多管理任务,否则这些任务可能极其困难或不可能。
Linux 几乎把所有东西都当作文件来处理。这有一些有趣和惊人的含义。这个概念使得复制整个硬盘成为可能,包括引导记录,因为整个硬盘是一个文件,就像单独的分区一样。
“一切都是一个文件”是可能的,因为所有的设备都是由 Linux 实现的,这些东西被称为设备文件。设备文件不是设备驱动程序;相反,它们是暴露给用户的设备的网关。
设备文件
设备文件在技术上被称为设备专用文件。 1 设备文件被用来提供操作系统,更重要的是,在开放的操作系统中,提供给用户一个到他们所代表的设备的接口。所有 Linux 设备文件都位于/dev 目录中,该目录是根(/)文件系统不可或缺的一部分,因为它们必须在引导过程的早期阶段(在挂载其他文件系统之前)对操作系统可用。
设备文件创建
udev 守护进程旨在简化/dev 目录中充斥着大量几乎不需要的设备的混乱局面。理解 udev 如何工作是处理设备,尤其是热插拔设备以及如何管理它们的关键。
/dev/目录一直是所有 Unix 和 Linux 操作系统中设备文件的位置。过去,设备文件是在创建操作系统时创建的。这意味着所有可能在系统中使用的设备都需要提前创建。事实上,需要创建成千上万的设备文件来处理所有的可能性。很难确定哪个设备文件实际上与特定的物理设备相关,或者某个设备是否丢失。
udev 简化
udev 旨在通过在/dev 中只为那些在引导时实际存在或者很可能实际存在于主机上的设备创建条目来简化这个问题。这大大减少了所需设备文件的总数。
此外,udev 会在设备插入系统时为其指定名称,例如 USB 存储器和打印机,以及其他非 USB 类型的设备。事实上,udev 将所有设备都视为即插即用,或者像有些人喜欢说的那样,即插即用,甚至在启动时也是如此。这使得在任何时候处理设备都是一致的,无论是在引导时还是以后热插拔时。
让我们用一个实验来看看这是如何工作的。
实验 5-1
以 root 用户身份执行此实验。
插上之前准备好的 u 盘。如果您使用的是虚拟机,您可能还必须使该设备对虚拟机可用。
输入这些命令。
[root@testvm1 dev]# cd /dev ; ls -l sd*
brw-rw---- 1 root disk 8, 0 Nov 22 03:50 sda
brw-rw---- 1 root disk 8, 1 Nov 22 03:50 sda1
brw-rw---- 1 root disk 8, 2 Nov 22 03:50 sda2
brw-rw---- 1 root disk 8, 16 Nov 28 14:02 sdb
brw-rw---- 1 root disk 8, 17 Nov 28 14:02 sdb1
查看 USB 设备上的日期和时间,在我的主机中分别是/dev/sdb 和/dev/sdb1。USB 驱动器和该驱动器上分区的设备文件的创建日期和时间应该正好是设备插入 USB 端口的时间,并且不同于其他设备上在引导时创建的时间戳。你看到的具体结果会和我的不一样。
作为系统管理员,我们不需要为要创建的设备文件做任何其他事情。Linux 内核负责一切。只有在创建了设备文件/dev/sdb1 之后,才能挂载分区以访问其内容。
udev 的创始人之一 Greg Kroah-Hartman 写了一篇论文 2 ,提供了一些关于 udev 的细节以及它应该如何工作的见解。请注意,自从本文撰写以来,udev 已经变得更加成熟,一些东西也发生了变化,比如 udev 规则的位置和结构。无论如何,本文对 udev 和当前的设备命名策略提供了一些深刻而重要的见解。
命名规则
在 Fedora 和 CentOS 的现代版本中,udev 将其默认命名规则存储在/usr/lib/udev/rules.d 目录中的文件中,将其本地规则和配置文件存储在/etc/udev/rules.d 目录中。每个文件包含一组特定设备类型的规则。CentOS 6 和更早版本将全局规则存储在/lib/udev/rules.d/中。udev 规则文件的位置在您的发行版中可能会有所不同。
在 udev 的早期版本中,创建了许多本地规则集,包括一组网络接口卡(NIC)命名规则。由于每个网卡都是由内核发现并由 udev 第一次重命名的,因此在规则集中为网络设备类型添加了一条规则。最初这样做是为了在名称从“ethX”更改为更一致的名称之前确保一致性。
规则改变蓝调
使用 udev 进行持久即插即用命名的一个主要结果是,对于普通的非技术用户来说,事情变得容易多了。从长远来看,这是一件好事;然而,存在迁移问题,许多系统管理员过去和现在都不喜欢这些变化。
随着时间的推移,规则发生了变化,网络接口卡至少有三种明显不同的命名约定。这种命名上的差异造成了大量的混乱,在这些变化期间,许多配置文件和脚本不得不被多次重写。
例如,最初为 eth0 的 NIC 名称将从 eth 0 更改为 em1 或 p1p2,最后更改为 eno1。我在我的技术网站上写了一篇文章 3 ,详细介绍了这些命名方案及其背后的原因。
现在 udev 有了多个一致的默认规则来确定设备名,尤其是对于 NIC,不再需要在本地配置文件中存储每个设备的特定规则来保持一致性。
设备数据流
让我们看一下典型命令的数据流,以直观地了解设备专用文件是如何工作的。图 5-1 显示了一个简单命令的简化数据流。从诸如 Konsole 或 xterm 之类的 GUI 终端仿真器发出cat
/etc
/resolv.conf
命令会导致从磁盘读取 resolv.conf 文件,同时磁盘设备驱动程序处理设备特定的功能,例如在硬盘上定位文件并读取它。数据通过设备文件传递,然后从命令传递到伪终端 6 的设备文件和设备驱动程序,并在终端会话中显示。
图 5-1
使用设备专用文件简化数据流
当然,cat
命令的输出可以通过下面的方式重定向到一个文件,cat
/etc
/resolv.conf > /etc/resolv.bak
以创建该文件的备份。在这种情况下,图 5-1 左侧的数据流将保持不变,而右侧的数据流将通过/dev/sda2 设备文件、硬盘设备驱动程序,然后作为新文件 resolv.bak 返回到硬盘的/etc 目录中
这些设备专用文件使得使用标准流(STDIO)和重定向来访问 Linux 或 Unix 计算机上的任何设备变得非常容易。它们为每台设备提供一致且易于访问的界面。只需将数据流定向到设备文件,即可将数据发送到该设备。
关于这些设备专用文件,需要记住的最重要的一点是,它们不是设备驱动程序。它们被最准确地描述为设备驱动程序的入口或网关。数据从应用或操作系统传递到设备文件,然后设备文件将数据传递到设备驱动程序,设备驱动程序再将数据发送到物理设备。
通过使用这些独立于设备驱动程序的设备文件,用户和程序可以对主机上的每个设备拥有一致的接口。正如 Linus 所说,这就是如何使用通用工具对不同的事物进行操作。
设备驱动程序仍然负责处理每个物理设备的独特需求。然而,这超出了本书的范围。
设备文件分类
设备文件至少有两种分类方式。第一种也是最常用的分类是通常与设备相关的数据流类型。例如,tty 和串行设备被认为是基于字符的,因为数据流一次传输和处理一个字符或一个字节。硬盘等块类型设备以块为单位传输数据,通常是 256 字节的倍数。
让我们看看/dev/目录和其中的一些设备。
实验 5-2
这个实验应该以用户学生的身份进行。
打开一个终端会话,显示一长串/dev/目录。
[student@f26vm ~]$ ls -l /dev | less
<snip>
brw-rw---- 1 root disk 8, 0 Nov 7 07:06 sda
brw-rw---- 1 root disk 8, 1 Nov 7 07:06 sda1
brw-rw---- 1 root disk 8, 16 Nov 7 07:06 sdb
brw-rw---- 1 root disk 8, 17 Nov 7 07:06 sdb1
brw-rw---- 1 root disk 8, 18 Nov 7 07:06 sdb2
<snip>
crw--w---- 1 root tty 4, 0 Nov 7 07:06 tty0
crw--w---- 1 root tty 4, 1 Nov 7 07:06 tty1
crw--w---- 1 root tty 4, 10 Nov 7 07:06 tty10
crw--w---- 1 root tty 4, 11 Nov 7 07:06 tty11
<snip>
此命令的结果太长,无法在此完整显示,但是您将看到一个设备文件列表,其中包含它们的文件权限以及它们的主要和次要标识号。
ls
-l
命令的大量输出通过less
transformer 实用程序传输,让您可以翻阅结果;使用向上翻页、向下翻页和上下箭头键移动。键入 q 退出并退出less
显示。
实验 5-1 中显示的设备文件的删减列表只是我的 Fedora 工作站上/dev/目录中的几个。它们代表磁盘和 tty 类型的设备。注意输出中每行最左边的字符。带有“b”的是块类型设备,以“c”开头的是字符设备。
识别设备文件的更详细、更明确的方法是使用设备主设备号和次设备号。磁盘设备的主编号为 8,表示它们是 SCSI 块设备。请注意,所有 PATA 和 SATA 硬盘都由 SCSI 子系统管理,因为旧的 ATA 子系统由于其代码质量差,多年前就被认为是不可维护的。因此,以前被指定为“hd[a-z]”的硬盘现在被称为“sd[a-z]”。
在上面显示的小样本中,您大概可以推断出磁盘驱动器次要编号的模式。次要编号 0、16、32 等等直到 240 都是完整的磁盘编号。因此,major/minor 8/16 表示整个磁盘/dev/sdb,8/17 是第一个分区/dev/sdb1 的设备文件。数字 8/34 应该是/dev/sdc2。
上面列表中的 tty 设备文件的编号从 tty0 到 tty63 稍微简单一些。我发现 tty 设备的数量有点不协调,因为新 udev 系统的要点是只为那些实际存在的设备创建设备文件;我不知道为什么要这样做。然而,您也可以从图 5-2 中的列表中看到,所有这些设备文件都是在 11 月 7 日 07:06 创建的,也就是主机启动的时间。主机上的设备文件也应该有一个与上次引导时间相同的时间戳。
位于 Kernel.org 的 Linux 分配设备 4 文件是设备类型和主要及次要编号分配的官方注册表。它可以帮助您了解所有当前定义的设备的主要/次要编号。
设备文件的乐趣
现在,让我们花几分钟时间来研究一下这些设备文件。我们将进行几个有趣的实验,展示 Linux 设备文件的强大功能和灵活性。
大多数 Linux 发行版都有多个虚拟控制台,从 1 到 7,可以用来通过 shell 界面登录到本地控制台会话。可以使用 Ctrl-Alt-F1 组合键访问控制台 1,Ctrl-Alt-F2 组合键访问控制台 2,依此类推。
实验 5-3
在这个实验中,我们将展示简单的命令可以用来在设备之间发送数据,在这个例子中,不同的控制台和终端设备。以学生用户的身份执行此实验。
按下 Ctrl-Alt-F2 切换到控制台 2。在某些发行版中,登录信息包括与此控制台相关的 tty (Teletype)设备,但许多发行版没有。应该是 tty2,因为你在控制台 2。如果使用虚拟机的本地实例,您可能需要使用不同的组合键。
以学生身份登录控制台 2。然后使用who am i
命令——是的,就像这样,用空格——来确定哪个 tty 设备连接到这个控制台。
[student@f26vm ~]$ who am i
student tty2 2017-10-05 13:12
此命令还显示控制台上的用户登录的日期和时间。
在我们进一步进行这个实验之前,让我们看看/dev 中的 tty2 和 tty3 设备列表。我们通过使用一个集合[23]来做到这一点,以便只列出这两个设备。
[student@f26vm ~]$ ls -l /dev/tty[23]
crw--w---- 1 root tty 4, 2 Oct 5 08:50 /dev/tty2
crw--w---- 1 root tty 4, 3 Oct 5 08:50 /dev/tty3
在引导时定义了大量的 tty 设备,但是在这个实验中我们并不关心它们中的大多数,只关心 tty2 和 tty3 设备。作为设备文件,它们没有什么特别的,它们只是简单的字符型设备;请注意结果第一列中的“c”。我们将在这个实验中使用这两台 TTY 设备。tty2 设备连接到虚拟控制台 2,tty3 设备连接到虚拟控制台 3。
按下 Ctrl-Alt-F3 切换到控制台 3,再次以学生用户身份登录。再次使用who am i
命令验证您确实在控制台 3 上,然后输入 echo 命令。
[student@f26vm ~]$ who am i
student tty3 2017-10-05 13:18
[student@f26vm ~]$ echo "Hello world" >
/dev
/tty2
按下 Ctrl-Alt-F2 返回控制台 2。控制台 2 上应该显示字符串“Hello world”(不带引号)。
这个实验也可以用 GUI 桌面上的终端模拟器来执行。桌面上的终端会话使用/dev 树中的伪终端设备,例如/dev/pts/1,其中 pts 代表“伪终端会话”。
使用 Konsole、Tilix、Xterm 或您喜欢的其他图形终端模拟器,在 GUI 桌面上打开至少两个终端会话。如果你愿意,你可以打开几个。使用我是谁命令确定它们连接到哪个伪终端设备文件,然后选择一对终端仿真器用于本实验。使用 echo 命令将消息发送给另一个。
[student@f26vm ~]$ who am i
student pts/9 2017-10-19 13:21 (192.168.0.1)
[student@f26vm ~]$ w
13:23:06 up 14 days, 4:32, 9 users, load average: 0.03, 0.08, 0.09
USER TTY LOGIN@ IDLE JCPU PCPU WHAT
student pts/1 05Oct17 4:48m 0.04s 0.04s -bash
student pts/2 06Oct17 2:16 2.08s 2.01s screen
student pts/3 07Oct17 12days 0.04s 0.00s less
student pts/4 07Oct17 2:16 0.10s 0.10s /bin/bash
root pts/5 08:35 4:08m 0.05s 0.05s /bin/bash
root pts/6 08:35 4:47m 1:19 1:19 htop
root pts/7 08:35 4:40m 0.05s 0.05s /bin/bash
root pts/8 08:50 4:32m 0.03s 0.03s /bin/bash
student pts/9 13:21 0.00s 0.04s 0.00s w
[student@f26vm ~]$ echo "Hello world" >
/dev
/pts/4
在我的测试主机上,我将文本“Hello world”从/dev/pts/9 发送到/dev/pts/4。您的终端设备将与我在测试虚拟机上使用的不同。请确保在您的环境中使用正确的设备进行本实验。
另一个有趣的实验是使用 cat 命令将文件直接打印到打印机上。
实验 5-4
这个实验应该以学生用户的身份进行。
您可能需要确定哪个设备是您的打印机。如果你的打印机是 USB 打印机,现在几乎都是,在/dev/usb 目录中查找 lp0,它通常是默认的打印机。您也可以在该目录中找到其他打印机设备文件。
我用 LibreOffice Writer 创建了一个简短的文档,然后导出为 PDF 文件,test.pdf。任何 Linux 文字处理器都可以,只要它能导出到 PDF 格式。
我们将假设您的打印机设备是/dev/usb/lp0,并且您的打印机可以直接打印 PDF 文件,大多数打印机都可以。请务必使用 PDF 文件,并将命令中的名称 test.pdf 改为您自己的文件名。
[student@f26vm ~]$ cat test.pdf >
/dev
/usb/lp0
此命令应该在您的打印机上打印 PDF 文件 test.pdf。
/dev 目录包含一些非常有趣的设备文件,这些文件是硬件的入口,人们通常不认为这些硬件是硬盘或显示器之类的设备。例如,系统内存——RAM——通常不被认为是“设备”,但是/dev/mem 是设备专用文件,通过它可以实现对内存的直接访问。
实验 5-5
这个实验必须以 root 用户的身份运行。因为你只是在读取内存的内容,所以这个实验没有什么危险。
注意一些测试人员报告说这个实验对他们不起作用。我没有在几个物理和虚拟主机上发现任何问题。请注意,这个实验可能会产生一个权限错误,而不是期望的输出。
如果根终端会话尚不可用,请打开终端模拟器会话,并以 root 用户身份登录。下一个命令将把第一个 200K 的 RAM 转储到 STDOUT。
[root@f26vm ~]# dd if=/dev/mem bs=2048 count=100
它可能看起来不像那么多,你所看到的将是难以理解的。为了使它更容易理解——至少以专家可以理解的适当格式显示数据——通过 od 实用程序传输前面命令的输出。
[root@f26vm ~]# dd if=/dev/mem bs=2048 count=100 | od -c
Root 用户比非 root 用户有更多的读取内存的权限,但是大多数内存是受保护的,不会被任何用户写入,包括 root 用户。
与简单地使用cat
命令转储所有内存相比,dd
命令提供了更多的控制,我也尝试过这样做。dd
命令提供了指定从/dev/mem 中读取多少数据的能力,也允许我指定从内存中读取数据的起始点。尽管使用cat
命令读取了一些内存,但内核最终还是响应了图 5-2 中的错误。
您也可以以非 root 用户学生的身份登录,并尝试此命令。您将得到一条错误消息,因为您试图访问的内存不属于您的用户。这是 Linux 的一个内存保护特性,可以防止其他用户读取或写入不属于他们的内存。
图 5-2
当 cat 命令试图将受保护的内存转储到 STDOUT 时,最后一行显示错误
这些内存错误意味着内核正在通过保护属于其他进程的内存来完成它的工作,这正是它应该如何工作。因此,尽管您可以使用/dev/mem 来显示存储在 RAM 内存中的数据,但是对大多数内存空间的访问是受保护的,并且会导致错误。只有内核内存管理器分配给运行dd
命令的 bash shell 的虚拟内存应该是可访问的,而不会导致错误。抱歉,你不能窥探不属于你的内存,除非你发现一个漏洞利用。
许多类型的恶意软件依靠特权提升来允许它们读取它们通常无法访问的内存内容。这使得恶意软件能够找到并窃取个人数据,如账号、用户 ID 和存储的密码。幸运的是,Linux 可以防止非根用户访问内存。它还可以防止特权升级。
但是即使是 Linux 安全也不是完美的。安装安全补丁来防止允许权限提升的漏洞是很重要的。你还应该意识到人为因素,比如人们写下密码的倾向,但那都是另一回事了。 5
现在,您可以看到内存也被视为一个文件,并且可以使用内存设备文件来处理它。
随机性、零等等
/dev 中还有一些其他非常有趣的设备文件。设备专用文件 null、zero、random 和 urandom 不与任何物理设备相关联。这些设备文件提供了零、空值和随机数的来源。
空设备/dev/null 可以用作重定向 shell 命令或程序输出的目标,这样它们就不会显示在终端上。
实验 5-6
我经常在我的 bash 脚本中使用/dev/null 来防止用户看到可能让他们感到困惑的输出。输入以下命令,将输出重定向到空设备。终端上不会显示任何内容。数据只是被转储到天空中的大比特桶中。
[student@f26vm ~]$ echo "Hello world" > /dev/null
将/dev/null 作为“空”字符的来源。
[student@testvm1 ~]$ cat /dev/null
[student@testvm1 ~]$ dd if=/dev/null
0+0 records in
0+0 records out
0 bytes copied, 5.2305e-05 s, 0.0 kB/s
/dev/null 实际上没有可见的输出,因为 null 设备只是返回一个文件结束(EOF)字符。请注意,字节计数为零。空设备作为一个重定向不需要的输出以便将其从数据流中删除的地方要有用得多。
/dev/random 和/dev/urandom 设备都是有用的数据流源。顾名思义,它们都产生随机输出——不仅仅是数字,而是任何和所有的字节组合。/dev/urandom 设备产生确定性的 6 随机输出,速度非常快。
实验 5-7
使用此命令查看/dev/urandom 的典型输出。可以用 Ctrl-c 突围。
[student@f26vm ~]$ cat /dev/urandom
,3••VwM
N•g•/•l•ۑ•!••'۩'•:••|R••[•t••Z••F.:H•7•,••
••z/••|•7q•Sp•"•(l_c••π••-•••••••ś•Y•••D⁵•i8••"%•••&ŋ|C9!y•••f•5bPp;••C
••x••1•••U••3~•••
<snip>
我只展示了该命令的一部分数据流,但是它应该会让您对您的系统有所了解。
您还可以通过od
命令来传输实验 5-6 的输出,使其更易于阅读。这对大多数现实世界的应用来说没有什么意义,因为它毕竟是随机数据。
od
的手册页显示,它可以用来直接从文件中获取数据,以及指定要读取的数据量。
实验 5-8
在这种情况下,我使用-N 128 将输出限制为 128 字节。
[student@f26vm ~]$ od /dev/urandom -N 128
0000000 043514 022412 112660 052071 161447 057027 114243 061412
0000020 154627 105675 154470 110352 135013 127206 103057 136555
0000040 033417 011054 014334 040457 157056 165542 027255 121710
0000060 125334 065600 165447 165245 020756 101514 042377 132156
0000100 116024 027770 000537 014743 170561 011122 173454 102163
0000120 074301 104771 123476 054643 105211 151753 166617 154313
0000140 103720 147660 012644 037363 077661 076453 104161 033220
0000160 056501 001771 113557 075046 102700 043405 132046 045263
0000200
dd
命令也可用于指定从[u]个随机设备获取的数据量的限制,但它不能直接格式化数据。
/dev/random 设备文件产生不确定的 7 随机输出,但它产生输出的速度较慢。该输出不是由仅依赖于先前生成的数字的算法确定的,而是响应于击键和鼠标移动而生成的。这种方法使得复制一系列特定的随机数更加困难。使用 cat 命令查看/dev/random 设备文件的一些输出。尝试移动鼠标,看看它如何影响输出。
从/dev/random 和/dev/urandom 生成的随机数据,不管是如何从这些设备中读取的,通常都被重定向到某个存储介质上的文件或另一个程序的 STDIN。系统管理员、开发人员或最终用户很少需要查看随机数据。但它确实为这个实验做了一个很好的示范。
顾名思义,/dev/zero 设备文件产生一个无休止的零字符串作为输出。请注意,这些是八进制零,而不是 ASCII 字符零(0)。
实验 5-9
使用dd
命令查看/dev/zero 设备文件的一些输出。请注意,该命令的字节数不为零。
[student@f26vm ~]$ dd if=/dev/zero bs=512 count=500 | od -c
0000000 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
*
500+0 records in
500+0 records out
256000 bytes (256 kB, 250 KiB) copied, 0.00126996 s, 202 MB/s
0764000
备份主引导记录
例如,考虑对硬盘驱动器的主引导记录(MBR)进行备份的简单任务。有时,我需要恢复或重新创建我的 MBR,尤其是分区表。从头开始重新创建它是非常困难的。从保存的文件中恢复它很容易。所以我们备份一下硬盘的开机记录。
请注意,本节中的所有实验都必须以 root 用户身份执行。
实验 5-10
我们将为您的主引导记录(MBR)创建一个备份,但不会尝试恢复它。
dd
命令必须以 root 身份运行,因为出于安全原因,非 root 用户不能访问/dev 目录中的硬盘设备文件。bs 值不是你可能想的那样;它代表块大小。Count 是从源文件中读取的块数。
[root@f26vm ~]# dd if=/dev/sda of=/tmp/myMBR.bak bs=512 count=1
这个命令在/tmp 目录中创建一个文件 myMBR.bak。该文件大小为 512 字节,包含 MBR 的内容,包括引导代码和分区表。
现在看看您刚刚创建的文件的内容。
[root@testvm1 ~]# cat /tmp/myMBR.bak
•c•••••••••|••••!••8u
Z••••••}•f••d•@f•D•••••••@•••••f•f•`|fL••uNf•\|f1•f•4••1•f•t;}7•••0••••Z••p••1••r••`•••1••••••a•&Z|••}•••}•4••}•.•••GRUB GeomHard DiskRead Error
••••<u••}•••• !••( •)•••• ••U•[root@testvm1 ~]#
因为在引导扇区的结尾没有行尾字符,所以命令提示符与引导记录的结尾在同一行。
如果 MBR 损坏了,就需要启动到一个救援盘,并使用代码示例 5-1 中的命令来执行与上面的命令相反的操作。请注意,不需要像第一个命令那样指定块大小和块数,因为 dd 命令只是将备份文件复制到硬盘驱动器的第一个扇区,并在到达源文件末尾时停止。
代码示例 5-1
以下代码将备份主引导记录还原到硬盘上的第一个扇区。
[root@testvm1 ~]# dd if=/tmp/myMBR.bak of=/dev/sda
不要运行此代码,因为如果输入不正确,它可能会损坏您的系统。
现在,您已经备份了硬盘的引导记录并验证了该备份的内容,让我们转移到一个更安全的环境,销毁引导记录,然后恢复它。
实验 5-11
这是一个相当长的实验,必须以 root 用户身份执行。您将为 USB 设备备份 MBR,损坏设备上的 MBR,尝试读取设备,然后恢复 MBR。不要安装 USB 驱动器。
确保 USB 驱动器已插入您的计算机,并验证设备文件名。在我的例子中,它仍然是/dev/sdb。
首先我们用fdisk
看分区表,为后面的对比提供依据,然后我们备份 USB 设备的 MBR,验证备份文件的内容。与之前的类似实验一样,警告消息是 MBR 内容的一部分。
[root@testvm1 ~]# fdisk -l /dev/sdb
Disk /dev/sdb: 62.5 MiB, 65536000 bytes, 128000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x73696420
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 127999 125952 61.5M c W95 FAT32 (LBA)
[root@f26vm ~]# dd if=/dev/sdb of=/tmp/myMBR.bak bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.012374 s, 41.4 kB/s
[root@f26vm ~]# cat /tmp/myMBR.bak
•>•MSWIN4.1P•} •••)L•0NO NAME FAT16 •}•3•••{•x•vVU•"•~•N•
•••|•E••F•E••8f$|•r<•F••fFVF•PR•F•V•• •v••^
•H••F•N•ZX••••rG8-t• V•v>•^tJNt
••F•V••S••[r•?MZu•••BJu••pPRQ••3••v••vB•••v••V$•••••••t<•t •••••}••}••3••^••D•••}•}••r••HH•N ••YZXr @uB^
•••'
Invalid system disk•
Disk I/O error•
Replace the disk,!••U•
现在有趣的部分来了,我们用一个 512 字节的随机数据块覆盖 USB 设备的 MBR,然后查看 MBR 的新内容以验证更改。请注意,警告消息不再存在,因为它们已被覆盖。
[root@f26vm ~]# dd if=/dev/urandom of=/dev/sdb bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.0195473 s, 26.2 kB/s
[root@f26vm ~]# dd if=/dev/sdb bs=512 count=1
6••••%•w••pI!8k•••••$••Q••¯••••gO••\••AT••KQ••••• ••"5•oW-•••;•••••ٹr3••oiP•d•q••••a••%••••N••#••&F•_•••y••?•\•••)••K••?•fa••+.••••F•'F••~•H•••XbS•••BA•V•^••z[S•jy••••••=aPs:••N_[ڶ••••b••#%•;/•••,4•}9
0••7•••ٯF85••L•g••\•R4••••q••Kn|M••cy••ʗ••m•\••••yi{_o^•i•j K•nry2MMSeA•••p•^E•n•v•u2•/•A•Zb•••1••Ì•K5•3•x•K•ia•K?•Iw••••^•1f•••{3•p&E•••M••rbɠ••••••••• p••K•1+0 records in
1+0 records out
512 bytes copied, 0.0137811 s, 37.2 kB/s
在我们继续恢复这个 MBR 之前,让我们再做一些事情来测试这种状态。首先,我们使用fdisk
来验证 USB 驱动器不再有分区表,这意味着 MBR 已经被覆盖。
[root@f26vm ~]# fdisk -l /dev/sdb
Disk /dev/sdb: 62.5 MiB, 65536000 bytes, 128000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
尝试挂载原始分区将会失败。错误消息表明特殊设备不存在。这表明大多数特殊设备文件都是根据需要按需创建和删除的。
[root@f26vm ~]# mount /dev/sdb1 /mnt
mount: /mnt: special device /dev/sdb1 does not exist.
是时候恢复您之前备份的启动记录了。因为您使用 dd 命令小心地用随机数据只覆盖了包含驱动器分区表的 MBR,所以所有其他数据都保持不变。恢复 MBR 将使其再次可用。恢复 MBR,在设备上查看 MBR,然后挂载分区并列出内容。
[root@f26vm ~]# dd if=/tmp/myMBR.bak of=/dev/sdb
1+0 records in
1+0 records out
512 bytes copied, 0.0738375 s, 6.9 kB/s
[root@testvm1 ~]# fdisk -l /dev/sdb
Disk /dev/sdb: 62.5 MiB, 65536000 bytes, 128000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x73696420
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 127999 125952 61.5M c W95 FAT32 (LBA)
[root@f26vm ~]# mount /dev/sdb1 /mnt
[root@f26vm ~]# ls -l /mnt
total 380
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file0.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file1.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file2.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file3.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file4.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file5.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file6.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file7.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file8.txt
-rwxr-xr-x 1 root root 37001 Nov 7 08:23 file9.txt
哇——太酷了!这一系列实验旨在说明,您可以利用所有设备都可以被视为文件这一事实,从而以一些非常有趣的方式使用一些非常常见但功能强大的 CLI 工具。
没有必要用 sb=和 count=参数指定要复制的数据量,因为 dd 命令只复制可用的数据量,在本例中是一个 512 字节的扇区。
卸载 USB 设备,因为我们现在已经完成了。
一切都是一个文件的含义
“一切都是一个文件”的含义是深远的,比这里所能列出的要大得多。在前面的实验中,您已经看到了一些例子。但是这里有一个简短的列表,包含了这些以及更多。
-
克隆硬盘。
-
备份分区。
-
备份主引导记录(MBR)。
-
将 ISO 映像安装到 USB 拇指驱动器上。
-
与其他终端上的用户进行交流。
-
将文件打印到打印机。
-
更改/proc 伪文件系统中某些文件的内容,以修改正在运行的内核的配置参数。
-
用随机数据或零覆盖文件、分区或整个硬盘。
-
将不需要的命令输出重定向到一个空设备,在那里它将永远消失。
-
等等。等。等。
这里有太多的可能性,任何列表都只能触及表面。我确信你已经——或者将要——想出许多方法来更有创造性地运用这一哲学原则,远比我在这里讨论的要多得多。
摘要
它是文件系统的一部分。Linux 计算机上的一切都可以作为文件系统空间中的一个文件来访问。这样做的全部目的是能够使用通用工具来操作不同的东西——通用工具,如标准的 GNU/Linux 实用程序和对文件起作用的命令也将在设备上起作用——因为在 Linux 中,它们是文件。
维基百科,设备文件, https://en.wikipedia.org/wiki/Device_file
2
Greg Kroah-Hartman,Linux Journal,内核科尔纳–udev–用户空间中的持久命名, http://www.linuxjournal.com/article/7316
3
大卫既,网卡名称赋值, http://www.linux-databook.info/?page_id=4243
4
https://www.kernel.org/doc/html/v4.11/admin-guide/devices.html
5
Apress 在 https://www.apress.com/us/security
有很多关于安全的好书
6
确定性意味着输出由已知算法确定,并使用种子字符串作为起点。每个输出单元都依赖于前一个输出和算法,因此如果您知道种子和算法,就可以复制整个数据流。因此,如果原始种子是已知的,黑客就有可能(尽管很难)复制输出。
7
非确定性结果不依赖于随机数据流中的先前数据。因此,它们比确定性的更具有真正的随机性。
六、使用 Linux FHS
Linux 文件系统分层标准(FHS)定义了 Linux 目录树的结构。它命名了一组标准目录并指定了它们的用途。
这个标准已经到位,以确保 Linux 的所有发行版在目录使用上是一致的。这种一致性使得系统管理员更容易编写和维护 shell 和编译程序,因为程序、它们的配置文件和它们的数据(如果有的话)应该位于标准目录中。本章介绍在目录树中的标准和推荐位置存储程序和数据,以及这样做的好处。您将学习如何参考 Linux FHS 文档,并在解决问题时使用这些知识。
定义
在我们深入探讨这个主题之前,让我们先给出“文件系统”这个词的一些定义,并尝试整理一下您可能会发现的一些术语混淆。您可能会听到人们以许多不同的、令人困惑的方式谈论文件系统。这个词本身可能有多种含义,你可能必须从讨论或文件的上下文中辨别正确的含义。
我将根据我观察到的“文件系统”一词在不同环境中的用法,尝试定义它的各种含义。请注意,虽然我试图符合标准的“官方”含义,但我的意图是基于该术语的各种用法来定义它。
-
从顶层(/)根目录开始的整个 Linux 目录结构。
-
一种特定类型的数据存储格式,如 EXT3、EXT4、BTRFS、XFS 等。Linux 支持近 100 种文件系统,包括一些非常老的文件系统,以及一些最新的文件系统。每种文件系统类型都使用自己的元数据结构来定义数据的存储和访问方式。
-
用特定类型的文件系统格式化的分区或逻辑卷,可以挂载在 Linux 文件系统上的指定挂载点(目录)上。
在本章的某个地方,我将在所有这些定义的上下文中使用术语“文件系统”。
标准
作为系统管理员,我们的任务包括从修复问题到编写 CLI 程序来为我们和他人执行许多任务。了解各种类型的数据应该存储在 Linux 系统的什么地方,对于解决问题和预防问题非常有帮助。
最新的文件系统层次标准(3.0) 1 在 Linux 基金会维护的文档中定义。这份文件在他们的网站上有多种格式,就像 FHS 的历史版本一样。
表 6-1 提供了标准的、众所周知的、已定义的顶级 Linux 目录及其用途的简要列表。这些目录是按字母顺序排列的。我建议您阅读整个文档,以便理解这些顶层子目录所扮演的角色。
注意表 6-1 中的第 2 列,中间一列。该列中所有带有“Yes”的目录都必须是根(/)文件系统不可分割的一部分。这些目录都不能位于单独的分区或逻辑卷上;它们必须与根文件系统位于同一个分区或逻辑卷中,因为它们是根文件系统不可分割的一部分。这些目录必须在引导过程开始时作为一个单元与根文件系统一起挂载。
第 2 列中带有“否”的目录可以创建在单独的分区或逻辑卷上——它们不必是单独的,但可以是单独的。当这些文件系统与根文件系统分离时,它们会根据/etc/fstab 文件中包含的信息在启动序列中稍后被挂载。将这些目录作为独立的文件系统安装有一些很好的理由,我将在本章后面讨论这些理由。
表 6-1
Linux 文件系统层次标准的顶层
|目录
|
属于/
|
描述
|
| — | — | — |
| /(根文件系统) | 是 | 根文件系统是文件系统的顶级目录。在挂载其他文件系统之前,它必须包含引导 Linux 系统所需的所有文件。系统启动后,所有其他文件系统都挂载在标准的、定义良好的挂载点上,作为根文件系统的子目录。 |
| /bin | 是 | /bin 目录包含用户可执行文件。 |
| /boot | 不 | 包含引导 Linux 计算机所需的静态引导加载程序、内核可执行文件和配置文件。 |
| /开发 | 是 | 该目录包含连接到系统的每个硬件设备的设备文件。这些不是设备驱动程序,而是代表计算机上每个设备并便于访问这些设备的文件。 |
| /等等 | 是 | 包含主机的各种系统配置文件。 |
| /home | 不 | 用户文件的主目录存储。每个人类用户通常在/home 中有一个子目录。一些组织可能会为用户的主目录选择其他位置。一些服务或服务器应用也可能使用不同的主目录位置。例如,Apache web 服务器使用/var/www。您可以查看/etc/passwd 文件来查看这些用户的主目录位置。使用中央文件服务器的安装也可能将这些远程主目录放在/home 以外的挂载点上。 |
| /库 | 是 | 包含引导系统所需的共享库文件。 |
| /媒体 | 不 | 安装外部可移动媒体设备(如可能连接到主机的 USB 拇指驱动器)的地方。 |
| /mnt | 不 | 常规文件系统(如不可移动介质)的临时挂载点,可在管理员修复或处理文件系统时使用。 |
| /opt | 不 | 供应商提供的应用等可选文件应位于此处。 |
| /proc | 虚拟的 | 虚拟文件系统用于公开对内部内核信息和可编辑调优参数的访问。 |
| /root | 是 | 这不是根(/)文件系统。它是根用户的主目录。 |
| /sbin | 是 | 系统二进制文件。这些是用于系统管理的可执行文件。 |
| /selinux | 虚拟的 | 这个伪文件系统仅在启用 SELinux 时使用。激活时,这个文件系统包含重要的 SELinux 工具和文件。 |
| /sys | 虚拟的 | 这个虚拟文件系统包含关于 USB 和 PCI 总线以及连接到每个总线的设备的信息。 |
| /tmp | 不 | 临时目录。由操作系统和许多程序用来存储临时文件。用户也可以在这里临时存储文件。请注意,此处存储的文件可能会在不事先通知的情况下随时删除。 |
| /usr | 不 | 这些是可共享的只读文件,包括可执行二进制文件和库、人工文件和其他类型的文档。 |
| /usr/local | 不 | 这些通常是 shell 程序或编译程序及其支持配置文件,它们在本地编写,由系统管理员或主机的其他用户使用。 |
| /var | 不 | 可变数据文件存储在这里。这可能包括日志文件、MySQL 和其他数据库文件、web 服务器数据文件、电子邮件收件箱等等。 |
/media 和/mnt 目录是临时文件系统维护或外部设备(如包含文件系统的 USB 拇指驱动器)的挂载点。
关于表 6-1 的“顶层”声明实际上有一个例外。这是/usr/local 目录。我将在本章稍后更详细地讨论这个目录。
使用定义良好的文件系统结构
遵循 Linux 文件系统分层标准有一些很好的理由。所有这些都让我们作为系统管理员的生活变得更加轻松。别担心,我不会讨论标准中定义的每个目录的功能——毕竟,你可以像我一样轻松地阅读我写的内容和更详细的在线版本。我要做的是讨论这个 FHS 的几个具体特征如何影响我的工作。
Linux FHS 的目的是提供一个定义良好的结构来存储文件,无论是可执行文件、数据还是配置文件。在文件系统分层标准(3.0)文档中定义的结构,以及前面提到的,阐述了 Linux 中文件位置的指导原则,这些原则基于可追溯到 Unix 早期的历史背景,以及新的、更新的和不断变化的标准和约定。
事实是用法确实会改变。文件系统层次标准也随着时间的推移而改变。此外,并不是所有的发行版和软件供应商都以相同的方式解释 FHS,一些软件供应商可能只是不了解这个标准。
不管这些事实如何,作为系统管理员,我们有责任在我们控制的所有方面坚持当前的标准。我们不能总是控制供应商的使用,但我们当然可以有我们的发言权。不要误解我——我在这里没有看到广泛的问题,但是如果有问题,我认为作为负责任的系统管理员,我们应该向适当的供应商报告这些问题。
当我们编写代码时,我们自己也应该遵守这些标准,即使它看起来只是 CLI 编程中的一小段无关紧要的代码。
Linux 统一目录结构
Linux 文件系统目录结构由可挂载文件系统的层次结构组成,这是本章开头列表中的第 3 项。这使得对层次结构中所有目录的访问更加容易和一致。它也提供了一些非常有用的副作用。
在一些非 Linux PC 操作系统中,如果有多个物理硬盘驱动器或多个分区,每个磁盘或分区都会分配一个驱动器号。有必要知道文件或程序位于哪个硬盘上,例如 C:或 D:。然后,您将驱动器号作为命令 D:发出,例如,切换到 D:驱动器,然后您使用cd
命令切换到正确的目录,以定位所需的文件。每个硬盘都有自己独立完整的目录树。
Linux 文件系统将所有物理硬盘驱动器、分区和逻辑卷统一到一个目录结构中。这一切都从顶部开始——根(/)目录。所有其他目录及其子目录都位于单个 Linux 根目录下。这意味着只有一个单一的目录树来搜索文件和程序。
这样做的唯一原因是,可以在独立的物理硬盘驱动器、不同的分区或与/(根)文件系统不同的逻辑卷上创建文件系统,比如/home、/tmp、/var、/opt 或/usr,然后将其作为根文件系统目录树的一部分挂载到一个挂载点上。挂载点只是空目录,没有什么特别的。甚至像 USB 拇指驱动器、外部 USB 或 ESATA 硬盘这样的可移动驱动器也将被安装到根文件系统上,并成为该目录树不可分割的一部分。
在从一个版本的 Linux 发行版升级到另一个版本,或者从一个发行版换到另一个发行版的过程中,这样做的一个很好的理由是显而易见的。一般来说,除了像 Fedora 中的 dnf-upgrade 这样的升级实用程序之外,明智的做法是在升级期间偶尔重新格式化根分区和包含操作系统的其他分区,以积极地删除任何随着时间积累的 cruft。如果/home 是根文件系统的一部分,它也将被重新格式化,然后必须从备份中恢复。通过将/home 作为一个单独的文件系统,安装程序将知道它是一个单独的文件系统,并且可以跳过对该文件系统的格式化。这也适用于存储数据库、电子邮件收件箱、网站和其他可变用户和系统数据的/var,以及用于存储商业应用的/opt 文件系统。因此,没有任何数据丢失,应用不应该需要重新安装,除非供应商非常愚蠢。
将 Linux 目录树的某些部分作为单独的文件系统来维护还有其他原因。例如,很久以前,当我还没有意识到将所有必需的 Linux 目录作为/(根)文件系统的一部分的潜在问题时,我设法用大量非常大的文件填满了我的主目录。因为/home 目录和/tmp 目录都不是独立的文件系统,而只是根文件系统的子目录,所以整个根文件系统都被填满了。没有空间留给操作系统来创建临时文件或扩展现有的数据文件。起初,应用开始抱怨没有空间保存文件,然后操作系统本身开始表现得非常奇怪。引导到单用户模式并清除我的主目录中有问题的文件让我可以重新开始工作;然后,我使用一个非常标准的多文件系统设置重新安装了 Linux,并且能够防止整个系统崩溃再次发生。
我曾经遇到过这样的情况,Linux 主机继续运行,但是阻止用户使用 GUI 桌面登录。我能够使用命令行界面(CLI)在本地使用一个虚拟控制台登录,并使用 SSH 远程登录。问题是/tmp 文件系统已经满了,GUI 桌面需要的一些临时文件无法在登录时创建。因为 CLI 登录不需要在/tmp 中创建文件,所以空间不足并没有妨碍我使用 CLI 登录。在这种情况下,/tmp 目录是一个单独的文件系统,并且/tmp 逻辑卷所在的卷组中有大量的可用空间。我只是将/tmp 逻辑卷扩展到一个大小,以适应我对该主机上所需的临时文件空间量的新理解,问题就解决了。请注意,该解决方案不需要重新启动,并且一旦/tmp 文件系统扩大,用户就可以登录到桌面。
特殊文件系统
Linux 在运行时有一些特殊的文件系统,其中两个系统管理员特别感兴趣,/proc 和/sys。当 Linux 主机运行时,这些虚拟文件系统只存在于 RAM 中;它们不存在于任何物理磁盘上。因为它们只存在于 RAM 中,所以这些文件系统不像存储在硬盘上的文件系统那样是持久的。当计算机关闭时,它们会消失,每次 Linux 启动时,它们会重新创建。
在 Linux 主机中,每个特殊的文件系统都扮演着独特的角色。/proc 文件系统很可能是您作为系统管理员非常熟悉的一个文件系统,所以我们将对它进行一点探索。
/proc 文件系统
FHS 将/proc 文件系统定义为 Linux 存储有关系统、内核和主机上运行的所有进程的信息的位置。它旨在为内核提供一个暴露自身信息的地方,以便于访问系统数据。它还旨在提供对视图内核配置参数的访问,并在必要时修改其中的许多参数。
当用作进入操作系统状态及其系统和硬件视图的窗口时,它提供了对您作为系统管理员可能想要的几乎每一点信息的方便访问。
实验 6-1
为了获得最佳实验结果,必须以 root 用户身份执行。
让我们首先看看正在运行的 Linux 主机的/proc 文件系统的顶层内容。在您的主机上,您可能会看到颜色编码来区分文件和目录。
首先,看看数字条目。这些目录的名称是 PID 或进程 ID 号。这些 PID 目录中的每一个都包含关于它所代表的正在运行的进程的信息。
[root@testvm1 proc]# cd /proc ; ls
1 26533 666 828 cpuinfo modules
10 26561 669 83 crypto mounts
11 27 680 84 devices mtrr
12 29356 681 85 diskstats net
13 30 685 86 dma pagetypeinfo
14 30234 686 87 driver partitions
15 31 692 9 execdomains sched_debug
16 333 694 90 fb schedstat
17 361 695 91 filesystems scsi
18 4 697 927 fs self
19 401 7 928 interrupts slabinfo
2 402 707 929 iomem softirqs
20 412 708 934 ioports stat
21 413 740 937 irq swaps
22 433 741 940 kallsyms sys
23 434 749 941 kcore sysrq-trigger
24 517 756 942 keys sysvipc
25 543 764 947 key-users thread-self
26 6 765 948 kmsg timer_list
26465 615 766 966 kpagecgroup tty
26511 616 771 990 kpagecount uptime
26514 636 778 acpi kpageflags version
26521 637 780 asound latency_stats vmallocinfo
26522 639 783 buddyinfo loadavg vmstat
26524 641 8 bus locks zoneinfo
26526 647 80 cgroups mdstat
26527 661 81 cmdline meminfo
26532 664 82 consoles misc
/proc 目录中的每个文件都包含关于内核某个部分的信息。让我们来看看其中的两个文件,cpuinfo 和 meminfo。
cpuinfo 文件大部分是静态的。它包含所有已安装 CPU 的规格。
[root@testvm1 proc]# cat cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 58
model name : Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
stepping : 9
microcode : 0x19
cpu MHz : 3392.345
cache size : 8192 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid pni pclmulqdq monitor ssse3 cx16 sse4_1 sse4_2 popcnt aes xsave avx rdrand lahf_lm
bugs :
bogomips : 6784.69
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual power management:
来自 cpuinfo 文件的数据包括处理器 ID 和型号、其当前速度(MHz)以及可用于确定 CPU 特性的标志。如果您运行命令ls
-la cpuinfo,
,您将看到文件上的时间戳在不断变化。指示文件正在更新。
现在我们来看看内存。首先对 meminfo 文件进行 cat,然后使用free
命令进行比较。
[root@testvm1 proc]# cat meminfo
MemTotal: 4044740 kB
MemFree: 2936368 kB
MemAvailable: 3484704 kB
Buffers: 108740 kB
Cached: 615616 kB
SwapCached: 0 kB
Active: 676432 kB
Inactive: 310016 kB
Active(anon): 266916 kB
Inactive(anon): 316 kB
Active(file): 409516 kB
Inactive(file): 309700 kB
Unevictable: 8100 kB
Mlocked: 8100 kB
SwapTotal: 4182012 kB
SwapFree: 4182012 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 270212 kB
Mapped: 148088 kB
Shmem: 988 kB
Slab: 80128 kB
SReclaimable: 64500 kB
SUnreclaim: 15628 kB
KernelStack: 2272 kB
PageTables: 11300 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 6204380 kB
Committed_AS: 753260 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 73664 kB
DirectMap2M: 4120576 kB
[root@testvm1 proc]# free
total used free shared buff/cache available
Mem: 4044740 304492 2935748 988 804500 3484100
Swap: 4182012 0 4182012
/proc/meminfo 文件中有很多信息。像 free command 这样的程序会使用其中的一些数据。如果您想了解内存使用的完整情况,请查看/proc/meminfo。free 命令像许多其他核心实用程序一样,从/proc 文件系统中获取数据。
因为/proc 中的数据几乎是 Linux 内核和计算机硬件状态的即时图像,所以数据可能会快速变化。连续几次查看中断文件。
我建议您花一点时间将/proc/meminfo 文件中的数据与您在使用像free
和top
这样的命令时获得的信息进行比较。您认为这些实用工具和许多其他工具是从哪里获得信息的?就在/proc 文件系统中,这就是。
让我们更深入地看看 PID 1。像所有进程目录一样,它包含关于具有该 ID 的进程的信息。让我们来看看这些信息。
实验 6-2
让我们进入并查看/proc/1 目录的内容。然后使用cat
命令查看 cmdline 文件的内容。
[root@testvm1 proc]# cd 1 ; cat cmdline
/usr/lib/systemd/systemd--switched-root--system--deserialize24
我们可以从 cmdline 的内容中看出,这是 systemd,所有程序之母。在所有旧版本和一些当前版本的 Linux 上,PID 1 将是 init 程序。花些时间研究一下这个过程中其他一些文件和目录的内容。
还需要花一些时间来研究一些其他的 PID 目录。
/proc 文件系统中有大量可用的信息,可以很好地用来解决问题。事实上,对正在运行的内核进行动态更改而无需重启是一个强大的工具,它允许您对 Linux 内核进行即时更改,以解决问题、启用功能或调整性能。让我们看一个例子。
Linux 非常灵活,可以做很多有趣的事情。其中一件很酷的事情是,任何带有多个网络接口卡(NIC)的 Linux 主机都可以充当路由器。只需要一点知识、一个简单的命令和对 iptables 防火墙的一些修改。
路由是由内核管理的任务。所以打开(或关闭)它需要我们改变一个内核配置参数。幸运的是,我们不需要重新编译内核,这是在/proc 文件系统中公开内核配置的好处之一。我们将打开 IP 转发,它提供了内核的基本路由功能。
实验 6-3
这个小命令行程序将/proc/sys/net/ipv4 目录作为 PWD,打印应该为零(0)的 ip_forward 文件的当前状态;将其设置为“1”;然后打印它的新状态,应该是 1。路由现已打开。确保在一行中输入命令。
[root@testvm1 ipv4]# cd /proc/sys/net/ipv4 ; cat ip_forward ; echo 1 > ip_forward ; cat ip_forward
0
1
恭喜你!您已经改变了正在运行的内核的配置。
为了完成 Linux 主机作为路由器的全部功能的配置,需要对 iptables 防火墙或您可能使用的任何防火墙软件以及路由表进行额外的更改。这些改变将定义路由的细节,例如哪些分组被路由到哪里。虽然超出了本书的范围,但我已经写了一篇文章 3 详细介绍了如何配置路由表,如果你想了解更多信息,可以参考这篇文章。我还写了一篇文章 4 ,简要介绍了将 Linux 主机转变为路由器所需的所有步骤,包括在重启后保持 IP 转发。
当您在/proc 文件系统中时,请多看看——跟随您自己的好奇心去探索这个重要文件系统的不同领域。
警告
我有意选择修改一个我熟悉的内核参数,它不会对您的 Linux 主机造成任何伤害。当您探索/proc 文件系统时,您不应该做任何进一步的更改。
/sys 文件系统
/sys 目录是另一个虚拟文件系统,Linux 使用它来维护供内核和系统管理员使用的特定数据。/sys 目录为计算机硬件中的每种总线类型分级维护硬件列表。
快速浏览一下/sys 文件系统就可以看到它的基本结构。
实验 6-4
在这个实验中,我们简要地看一下/sys 目录的内容,然后是它的一个子目录/sys/block。
[root@testvm1 sys]# cd /sys ; ls
block bus class dev devices firmware fs hypervisor kernel module power
[root@testvm1 sys]# ls block
dm-0 dm-1 sda sr0
/sys/block 中有不同类型的磁盘(块)设备,sda 设备是其中之一。这通常是该虚拟机中的第一个硬盘,在这种情况下也是唯一的硬盘。让我们快速看一下 sda 目录的一些内容。
[root@testvm1 sys]# ls block/sda
alignment_offset events_async queue slaves
bdi events_poll_msecs range stat
capability ext_range removable subsystem
dev holders ro trace
device inflight sda1 uevent
discard_alignment integrity sda2
events power size
[root@testvm1 sys]# cat block/sda/dev
8:0
[root@testvm1 sys]# ls block/sda/device
block ncq_prio_enable
bsg power
delete queue_depth
device_blocked queue_ramp_up_period
device_busy queue_type
dh_state rescan
driver rev
eh_timeout scsi_device
evt_capacity_change_reported scsi_disk
evt_inquiry_change_reported scsi_generic
evt_lun_change_reported scsi_level
evt_media_change state
evt_mode_parameter_change_reported subsystem
evt_soft_threshold_reached sw_activity
generic timeout
inquiry type
iocounterbits uevent
iodone_cnt unload_heads
ioerr_cnt vendor
iorequest_cnt vpd_pg80
modalias vpd_pg83
model wwid
[root@testvm1 sys]# cat block/sda/device/model
VBOX HARDDISK
为了从这最后一个命令中获得更真实的信息,我还在我自己的物理硬盘上执行了这个操作,而不是在我在这些实验中使用的虚拟机上,看起来像这样。
[root@david proc]# cat /sys/block/sda/device/model
ST320DM000-1BD14
这些信息更像是您在自己的硬件主机上看到的,而不是在虚拟机上看到的。现在让我们使用smartctl
命令来显示同样的信息和更多的信息。由于更真实的数据,我使用了我的物理主机。我还削减了结果末尾的大量输出。
[root@david proc]# smartctl -x /dev/sda
smartctl 6.5 2016-05-07 r4318 [x86_64-linux-4.13.16-302.fc27.x86_64] (local build)
Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org
=== START OF INFORMATION SECTION ===
Model Family: Seagate Barracuda 7200.14 (AF)
Device Model: ST320DM000-1BD14C
Serial Number: Z3TT43ZK
LU WWN Device Id: 5 000c50 065371517
Firmware Version: KC48
User Capacity: 320,072,933,376 bytes [320 GB]
Sector Sizes: 512 bytes logical, 4096 bytes physical
Rotation Rate: 7200 rpm
Device is: In smartctl database [for details use: -P show]
ATA Version is: ATA8-ACS T13/1699-D revision 4
SATA Version is: SATA 3.0, 6.0 Gb/s (current: 6.0 Gb/s)
Local Time is: Wed Dec 13 13:31:36 2017 EST
SMART support is: Available - device has SMART capability.
SMART support is: Enabled
AAM level is: 208 (intermediate), recommended: 208
APM feature is: Unavailable
Rd look-ahead is: Enabled
Write cache is: Enabled
ATA Security is: Disabled, frozen [SEC2]
Wt Cache Reorder: Enabled
=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
General SMART Values:
<snip>
如果我没有切断最后一个命令的结果,它还会显示故障指示器和温度历史记录等信息,这有助于确定硬盘问题的来源。
smartctl
实用程序从/sys 文件系统获得它所使用的数据,就像其他实用程序从/proc 文件系统获得它们的数据一样。
如您所见,该目录中的数据包含大量关于设备的信息。
/sys 文件系统包含关于 PCI 和 USB 系统总线硬件以及任何附加设备的数据。例如,内核可以使用这个信息来确定使用哪个设备驱动程序。
实验 6-5
让我们来看看关于计算机上的一种总线 USB 总线的一些信息。我将直接跳到/sys 文件系统中设备的位置;你可能需要自己做一些探索来找到你感兴趣的项目。
[root@testvm1 ~]# ls /sys/bus/usb/devices/usb2
2-0:1.0 bMaxPacketSize0 driver quirks
authorized bMaxPower ep_00 removable
authorized_default bNumConfigurations idProduct remove
avoid_reset_quirk bNumInterfaces idVendor serial
bcdDevice busnum interface_authorized speed_default
bConfigurationValue configuration ltm_capable subsystem
bDeviceClass descriptors manufacturer uevent
bDeviceProtocol dev maxchild urbnum
bDeviceSubClass devnum power version
bmAttributes devpath product
上面的结果显示了提供有关该特定设备的数据的一些文件和目录。但是有一种更简单的方法,那就是使用核心实用程序,这样我们就不必自己去做所有的探索了。
[root@david ~]# lsusb
Bus 002 Device 005: ID 1058:070a Western Digital Technologies, Inc. My Passport Essential (WDBAAA), My Passport for Mac (WDBAAB), My Passport Essential SE (WDBABM), My Passport SE for Mac (WDBABW
Bus 002 Device 004: ID 05e3:0745 Genesys Logic, Inc. Logilink CR0012
Bus 002 Device 003: ID 1a40:0201 Terminus Technology Inc. FE 2.1 7-port Hub
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 005: ID 0bc2:ab1e Seagate RSS LLC Backup Plus Portable Drive
Bus 006 Device 003: ID 2109:0812 VIA Labs, Inc. VL812 Hub
Bus 006 Device 002: ID 2109:0812 VIA Labs, Inc. VL812 Hub
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 007: ID 2109:2812 VIA Labs, Inc. VL812 Hub
Bus 005 Device 004: ID 2109:2812 VIA Labs, Inc. VL812 Hub
Bus 005 Device 006: ID 04f9:0042 Brother Industries, Ltd HL-2270DW Laser Printer
Bus 005 Device 005: ID 04f9:02b0 Brother Industries, Ltd MFC-9340CDW
Bus 005 Device 003: ID 050d:0234 Belkin Components F5U234 USB 2.0 4-Port Hub
Bus 005 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 005: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 006: ID 17f6:0822 Unicomp, Inc
Bus 001 Device 003: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 010: ID 0424:4063 Standard Microsystems Corp.
Bus 003 Device 009: ID 0424:2640 Standard Microsystems Corp. USB 2.0 Hub
Bus 003 Device 008: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
我再次在我自己的物理主机上运行最后一个命令,因为它会产生更有趣的结果。
除 PCI 总线外,lspci
命令执行与lsusb
相同的功能。继续,自己尝试一下lspci
命令。
我有时发现查找特定的硬件设备很有帮助,尤其是新添加的设备。与/proc 目录一样,有一些核心实用程序,如lsusb
和lspci
,使我们可以轻松查看连接到主机的设备的信息。
防火墙
selinux 伪文件系统类似于其他伪文件系统,比如/proc。它可以位于/selinux 或/sys/fs/selinux。只有在启用 SELinux 时,才会创建和显示这个文件系统。
当/selinux 文件系统存在时,它包含与内核密切相关的文件,就像/proc 中的文件一样。当 SELinux 被启用时,这个文件系统提供了一个窗口来查看正在运行的内核的安全功能。
Fedora 和其他与 Red Hat 相关的发行版默认在目标模式下启用 SELinux。您的发行版可能已经关闭了它,或者像包括我在内的许多系统管理员一样已经关闭了它。下一个实验帮助我们探索 selinux 文件系统,但是我们首先需要了解一个已知的状态。
实验 6-6
注意仅在指定用于培训目的的主机或虚拟机上执行本实验。在任何情况下,都不要在生产主机上执行此实验。
如果您的主机启用了 SELinux,我们将在继续之前禁用它。首先让我们看看它是否被禁用。
[root@testvm1 ~]# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 31
SELinux 在我的 Fedora 主机上以目标模式启用。如果您的主机是这种情况,请记下为 SELinuxfs 挂载点指定的位置。还要记下当前的模式,应该是强制模式还是许可模式。
禁用 SELinux。用您喜欢的编辑器打开/etc/sysconfig/selinux 文件。将 SELINUX=行更改为 disabled。完成后,该文件应该如下所示。
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
现在重新启动主机。重新启动需要一些时间,因为 SELinux 必须从它所保护的文件系统的文件中删除它的标签。移除这些标签后,主机将再次重启。
主机重新启动后,以 root 用户身份登录。您可以在其中一个虚拟控制台中完成这项工作,因为实验的这一部分不需要 GUI。
每个人都应该执行这个实验的剩余部分,不管 SELinux 是启用还是禁用。
尝试在上面提到的位置找到 selinux 文件系统。它不应该出现。
[root@testvm1 ~]# ls -l /sys/fs/selinux
ls: cannot access '/sys/fs/selinux': No such file or directory
现在重新启用 SELINUX,方法是使用您的编辑器将 SELinux 行改回 enforcing 或 permissive,也就是我们第一次更改它之前的值。然后重新启动系统,并等待它完成第二次重新启动。
以 root 用户身份登录到虚拟控制台,或者登录到您喜欢的桌面。如果您登录到桌面,请以 root 用户身份打开终端仿真程序窗口。现在尝试查看 selinux 目录。
[root@testvm1 ~]# ls -l /sys/fs/selinux/
total 0
-rw-rw-rw-. 1 root root 0 Feb 3 2018 access
dr-xr-xr-x. 2 root root 0 Feb 3 2018 avc
dr-xr-xr-x. 2 root root 0 Feb 3 2018 booleans
-rw-r--r--. 1 root root 0 Feb 3 2018 checkreqprot
dr-xr-xr-x. 99 root root 0 Feb 3 2018 class
--w-------. 1 root root 0 Feb 3 2018 commit_pending_bools
-rw-rw-rw-. 1 root root 0 Feb 3 2018 context
-rw-rw-rw-. 1 root root 0 Feb 3 2018 create
-r--r--r--. 1 root root 0 Feb 3 2018 deny_unknown
--w-------. 1 root root 0 Feb 3 2018 disable
-rw-r--r--. 1 root root 0 Feb 3 2018 enforce
dr-xr-xr-x. 2 root root 0 Feb 3 2018 initial_contexts
-rw-------. 1 root root 0 Feb 3 2018 load
-rw-rw-rw-. 1 root root 0 Feb 3 2018 member
-r--r--r--. 1 root root 0 Feb 3 2018 mls
crw-rw-rw-. 1 root root 1, 3 Feb 3 2018 null
-r--r--r--. 1 root root 0 Feb 3 2018 policy
dr-xr-xr-x. 2 root root 0 Feb 3 2018 policy_capabilities
-r--r--r--. 1 root root 0 Feb 3 2018 policyvers
-r--r--r--. 1 root root 0 Feb 3 2018 reject_unknown
-rw-rw-rw-. 1 root root 0 Feb 3 2018 relabel
-r--r--r--. 1 root root 0 Feb 3 2018 status
-rw-rw-rw-. 1 root root 0 Feb 3 2018 user
--w--w--w-. 1 root root 0 Feb 3 2018 validatetrans
如果看不到 selinux 目录的内容,请验证位置是否正确,然后重试。
问题解决
我能想到的坚持 Linux FHS 的最好的理由之一是尽可能地使解决问题变得容易。使用 Linux 文件系统分层标准促进了一致性和简单性,这使得问题的解决更加容易。知道在 Linux 文件系统目录结构中的什么地方可以找到东西,这让我避免了多次无休止的摸索。
我发现我所使用的发行版中提供的大多数核心实用程序、Linux 服务和服务器在使用/etc 目录及其子目录存储配置文件时是一致的。这意味着为发行版提供的行为不当的程序或服务找到配置文件应该很容易。
我通常使用/etc 中的许多 ASCII 文本文件来配置 SendMail、Apache、DHCP、NFS、NTP、DNS 等等。我总是知道在哪里可以找到我需要为这些服务修改的文件,它们都是开放和可访问的,因为它们是 ASCII 文本,这使得它们对计算机和人类都是可读的。
注意
这似乎与 BIND DNS 不一致,因为它的 zone、reverse 和根提示文件 named.ca 都位于/var/named 中。这并不矛盾,因为那些不是配置文件,它们是数据库文件,正如你在表 6-1 中看到的,是/var 的功能之一。此外,那些“可变”文件可能被外部服务器修改,例如当主名称服务器更新辅助名称服务器的数据库时。让这些外部服务器远离我们计算机上的主配置目录/etc 是一个非常好的主意。
绑定数据库文件的位置与 FHS 一致。但我确实花了一段时间才弄明白为什么会这样,更不用说对 FHS 的广泛研究了。有时我的好奇心会带我走很长的弯路,但我总是从这些旅程中学到很多东西,这对后来很有用。
不正确地使用文件系统
当我在 Research Triangle Park 的一家大型技术公司担任实验室管理员时,发生了一个涉及文件系统使用不当的情况。我们的一个开发人员在错误的位置安装了一个应用。应用崩溃是因为/var 文件系统已满,而存储在该文件系统的/var/log 中的日志文件由于/var 中缺少空间而无法附加新消息来指示/var 文件系统已满。然而,由于关键的/ (root)和/tmp 文件系统没有填满,系统仍然保持正常运行。删除有问题的应用,并在/opt 文件系统中重新安装它,这样就解决了这个问题。我还和最初安装的开发人员讨论了一下。
电子邮件收件箱
有很多次,我需要解决电子邮件收件箱的问题。我发现一些垃圾邮件不符合适当的电子邮件标准,至少一些电子邮件客户端在查看和管理这些垃圾邮件以及电子邮件收件箱文件中的一些垃圾邮件时存在问题。
你知道电子邮件收件箱在电子邮件服务器上的什么位置吗?它在/var/spool/mail 中,那里的每个收件箱文件都有电子邮件用户 ID 的名称。凭借一点点运气和良好的研究,我能够通过删除令人讨厌的垃圾邮件来修复收件箱。
即使我从来不需要对特定服务的配置文件进行修改,我也知道它几乎总是可以在/etc 目录中找到。这大大减少了我需要做的搜索量。
坚持标准
那么,作为系统管理员,我们如何坚持 Linux FHS 呢?这其实很简单,在表 6-1 中有一个提示。/usr/local 目录是存储本地创建的可执行文件及其配置文件的地方。
对于本地程序,FHS 是指那些我们作为系统管理员自己创建的程序,以使我们的工作或其他用户的工作更容易。这包括我们编写的所有那些强大和通用的 Shell 程序。
这些程序应该位于/usr/local/bin 中,配置文件(如果有)应该位于/usr/local/etc 中。还有一个/var/local 目录,本地程序可以在其中存储自己的数据库文件。
这些年来,我写了相当多的 shell 程序,至少花了五年时间,我才明白在主机上安装我自己的软件的合适位置。在某些情况下,我甚至忘记了我把它们安装在哪里。在其他情况下,我将配置文件安装在/etc 而不是/usr/local/etc 中,并且我的文件在升级期间被覆盖。第一次发生的时候花了几个小时才追踪到。
通过在编写 shell 程序时遵守这些标准,我更容易记住我将它们安装在了哪里。对于其他系统管理员来说,通过只搜索我们作为系统管理员已经安装了这些程序及其文件的目录,也更容易找到东西。
________________________________
/ I have trouble remembering \
| where to put files, too. |
\ The FHS can help. /
----------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
这个文件放在哪里?
我过去安装简单的 Bash 程序时,只是简单地将文件复制到我工作的主机上的适当位置。有时我会忘记他们应该去哪里。随着程序数量的增加,我需要花费更多的时间来执行所有的任务,以安装越来越多的我自己的省时工具。
当我安装一台新计算机时,我发现了一个很好的方法来方便我的 shell 程序的安装,以及当它们需要被传播时的升级。我创建了一个 RPM,其中包含我的程序及其所有配置和其他辅助文件,以及放置每个文件的位置说明。RPM 还包含一个小的 Bash 脚本,它在安装后运行,以便执行某些配置任务,安装最新的更新,并安装一些我一直希望在我的 Linux 主机上安装的应用和实用程序,但安装程序通常不会安装它们。
从某种意义上说,创建这个 RPM 是懒惰的系统管理员的行为,自动安装大量的程序、字体、配置文件等等。有一段时间,我有太多的事情需要手动完成——通过终端上的单个命令——以至于我要花三四个小时的时间来完成这些任务。创建 RPM 后,现在需要几分钟运行 dnf 来安装 RPM。然后花一分钟时间输入命令来运行我编写的一个大型 Bash 程序,以执行我以前手工执行的所有其他安装、修改等等。shell 程序可能需要 20 分钟到一个小时左右才能运行完成,但是我不再需要监视每一个命令,所以我可以准备好手动运行下一个命令。我不需要悬停在计算机上;当自动化为我工作时,我可以去做其他更有效率的事情。
摘要
本章探讨了 Linux 文件系统。您已经了解到,分层目录结构具有适用于该结构中目录使用的标准。遵循由 Linux 基金会维护的 Linux 文件系统分层标准中概述的标准使用约定,为系统管理员提供了一些重要的好处。当目录树中包含数据的部分被创建为独立的文件系统并被单独挂载时,尤其如此。
Linux 文件系统不仅仅是存储程序和数据的地方。它是一个可以找到并充分利用有关操作系统、运行程序甚至硬件的数据和统计信息的地方。Linux FHS 定义了可以找到这些信息的目录,所以我们知道当我们需要时,这些信息会一直存在。
了解 Linux 文件系统中包含的内容及其位置是执行问题确定的一个不可或缺的工具。
http://refspecs.linuxfoundation.org/fhs.shtml
2
Linux 基金会维护着定义许多 Linux 标准的文档。它还赞助 Linus Torvalds 的工作。
3
大卫既,《Linux 网络路由导论》, https://opensource.com/business/16/8/introduction-linux-network-routing
4
大卫·博恩,《把你的 Linux 盒子变成路由器》, http://www.linux-databook.info/?page_id=697
5
我不喜欢主要和次要服务器的官方名称,所以不会使用它们。我认为无论如何,小学和中学更能说明问题。