精通 Linux 2
http://www.amazon.com/dp/1593275676/ref=rdr_ext_tmb
Review 注意事项:
1. 磁盘?硬盘?
2. 一些术语需要 google 确认
第一章 概述
Linux 这样的现代操作系统乍看起来都非常复杂,其内部有多得令人眼花缭乱的各种组件在同步
运行和相互通讯。比如:一个 Web 服务器可以联接到一个数据库服务器,他们之间可能使用了一
个很多其他程序也在使用的公共组件。这一切究竟是如何工作的?
理解一个操作系统的工作原理最好的方法是“抽象思维”,你可以暂时忽略大部分细节。就像坐车
一样,通常你不会去在意车内固定发动机的装配螺栓,也不会关心你正在经过的那条路是谁修筑
的。如果你是一个乘客的话,你可能只关心车要去哪、如何打开车门、怎样系好安全带。
但如果你在驾驶一辆汽车,你就需要了解更多的细节,比如:如何控制油门,怎样换挡,还有如
何处理意外情况。
如果我们觉得开车这个过程太复杂,就可以运用“抽象思维”来帮助理解。首先你可以将“一辆汽车
在路上行驶”抽象为三个部分:汽车,道路,以及你的驾驶操作。这样有助于将复杂的问题分解开
来。如果道路颠簸,你不会去埋怨车辆本身和你的驾驶技术。相反,你可能会想为什么这条路这
么烂,或者如果这是条新修的路的话,筑路工人的活干得可真够差劲的。
软件开发人员运用抽象思维来开发操作系统和应用程序。在计算机领域,我们用很多术语来描述
一个抽象的子系统,如:“子系统”,“模块”,和“包”。本书中我们使用“组件”这个相对简单的词。
在软件开发过程中,开发人员通常不太考虑他们需要使用的组件的内部结构,他们只关心能使用
哪些组件?怎么个用法?
本章概述了 Linux 操作系统涉及的主要组件。虽然每一个组件包含纷繁复杂的技术细节,我们将
暂时忽略这些细节,而专注于这些组件在系统中发挥的功能。
1.1 Linux 操作系统中的抽象级别和层次
在合理组织的前提下,通过抽象将系统分解为组件有助于了解其工作机制。我们将组件划分为层
(或者级别)。组件的层(或者级别)代表它在用户和硬件系统之间所处的位置。Web 浏览器、游
戏这些应用处于最高层,底层则是计算机硬件系统,如:内存.操作系统处于这两层之间。
Linux 操作系统主要分 3 层。如图 1-1 所示,最底层是硬件系统,包括内存和中央处理器(用于
计算和从内存中读写数据),此外硬盘和网络接口也是硬件系统的一部分。
硬件系统之上是内核,它是操作系统的核心。内核运行在内存中,向中央处理器发送指令。内核
管理硬件系统,是硬件系统和应用程序之间通讯的接口。
计算机中运行的所有进程(确切地说是用户进程,无论用户是否和它们有直接的交互)由内核统
一管理,它们组成了最顶层,称为用户空间。例如:Web 服务器就是以用户进程的形式运行的。
图例1-1 Linux 系统的基本组成
内核和用户进程之间最主要的区别是:内核运行在内核模式中,而用户进程运行在用户模式中。
在内核模式中运行的代码可以不受限地访问中央处理器和内存,这种模式功能强大,但也非常危
险,因为内核进程可以轻而易举地使整个系统崩溃。那些只有内核可以访问的空间我们称为内核
空间。
相对于内核模式,用户模式对内存和中央处理器有一定限度的访问权限,权限通常不是很大。用
户空间是那些用户进程能够访问的内存空间。如果一个用户进程出错并且崩溃的话,其导致的后
果也相对有限,并且能够被内核清除。例如:如果你的 Web 浏览器崩溃了,不会影响到你正在运
行的其他程序。
理论上来说,一个用户进程出问题并不会对整个系统造成严重的影响。当然这取决于我们如何定
义“严重的影响”,并且还取决于该进程拥有的权限。因为不同的进程拥有的权限可能不同,一些
进程能够执行一些别的进程无权执行的操作。举个例子,如果拥有足够的权限,用户进程可以将
硬盘上的数据全部清除,也许你会觉得这样太危险。操作系统提供了一些相关的安全措施,不过
大多数用户进程并没有这个权限。
1.2 硬件系统:理解主内存
主内存或许是所有硬件系统中最为重要的部分,主内存存储 0 和 1 这样的数据,我们称每一个 0
和 1 为一个比特(或字位)。内核和进程就在主内存里运行,它们由一系列 0 和 1 组成。所有外
围设备的输入和输出数据都通过主内存,同样是以一系列 0 和 1 的形式。中央处理器像一个操作
员一样处理内存中的数据,它从内存读取指令和数据,然后将运算结果写回到内存。
在我们谈论内存、进程、内核、和其他内容时你会经常看到“状态”这个词。严格说来,一个状态
就是一系列的比特值。例如:内存中 0110,0001 和 1011 三个比特值即表示三个不同的状态。
一个进程动辄由几百万个比特值组成,因而使用抽象词汇来描述状态可能比使用比特值更简单一
些。使用进程已经完成的任务或者当前正在执行的任务,如:“进程正在等待用户输入”或者“进程
正在执行启动任务的第二个阶段”。
注解:因为我们通常使用抽象词汇来描述状态,所以内存映像这个词则用来表示比特值在内存中
的排列。
1.3 内核
我们讨论主内存和状态的原因,是因为内核的几乎所有操作都和主内存相关。其中之一是将内存
划分为很多区块,并且始终保存这些区块的状态信息。每一个进程拥有自己的内存区块,内核必
须确保每个进程只使用它自己的那部分内存区块。
内核负责管理以下四个方面:
进程 - 内核决定哪个进程可以使用 CPU。
内存 - 内核管理所有的内存,哪一部分内存分配给了哪一个进程,哪些内存被多个进程共享,
哪些内存未被使用。
设备驱动程序 - 作为硬件系统和进程之间的接口,内核负责操控硬件设备。
系统调用和支持 - 进程通常使用系统调用和内核进行通讯。
下面我们详细介绍这四个方面。
注解:如果你对内核的详细工作原理感兴趣,可以参考《Operating System Concepts》, 9th
edition, by Abraham Silberschalz, Peter B. Galvin, and Greg Gagne, Wiley, 2012 和《Moden
Operating Systems》, 4th edition, by Andrew S. Tanenbaum and Herbert Bos, Prentice Hall,
2014
1.3.1 进程管理
进程管理涉及进程的启动,暂停,恢复和终止。启动和终止进程比较直观,但是要解释清楚进程
在执行过程中如何使用 CPU 则相对复杂一些。
在现代操作系统中,进程都是同步执行的。例如:你可以同时在桌面打开 Web 浏览器和电子表格
应用程序。虽然看上去是如此,实际上这些应用程序后面的进程并不是同步运行的。
我们设想一下在只有一个 CPU 的计算机系统中,可能会有很多进程使用该 CPU,但是在任何一
个特定的时间段内只能有一个进程可以使用该 CPU。所以实际上是多个进程轮流使用 CPU,每
个进程使用一段时间后就暂停,然后让另一个进程使用(通常是毫秒极),依次轮流。一个进程
让出 CPU 使用权给另一个进程的过程称为上下文切换。
进程在一个时间段内有足够的时间完成其主要的计算工作,通常进程在第一个时间段内就能完成
它当前的工作。由于时间段非常短,以至于我们根本察觉不到,所以在我们看来系统是在同时运
行多个进程。
内核负责上下文切换,我们来看一下下面的场景,以便理解它的工作原理:
1. CPU 为每个进程计时,到时即停止当前的进程,并切换至内核模式,由内核接管 CPU 控制
权。
2. 内核记录下当前 CPU 和内存的状态信息,这些信息在恢复当前被停止的进程时需要用到。
3. 内核执行上一个时间段内需要执行的任务。如:从输入输出设备获得数据,磁盘读写操作
等)。
4. 内核准备就绪可以执行下一个进程。内核从就绪进程列表中选择一个进程执行。
5. 内核为新进程准备 CPU 和内存。
6. 内核将新进程执行的时间段通知 CPU。
7. 内核将 CPU 切换至用户模式,将 CPU 控制权移交给新进程。
从以上步骤我们可以看出,内核是在进程的时间段间隙,上下文切换的时候运行的。
在多 CPU 系统中,情况要稍微复杂一些。如果新进程将在另一个 CPU 上运行,内核就不需要让
出当前 CPU 的使用权。不过为了最大化所有 CPU 的使用效率,内核会使用一些其他的方式来获
取 CPU 控制权。
1.3.2 内存管理
内核在上下文切换过程中管理内存,这个过程十分复杂,因为内核要保证以下所有条件:
● 内核需要自己的专有内存空间,其他的用户进程无法访问。
● 每个用户进程有自己的专有内存空间。
● 一个进程不能访问另一个进程的专有内存空间。
● 用户进程之间可以共享内存。
● 用户进程的某些内存空间可以是只读的。
● 通过使用磁盘交换,系统可以使用比实际内存容量更多的“内存”空间。
新型的 CPU 提供了内存管理工具(MMU),MMU 使用了一种内存访问机制叫虚拟内存(virtual
memory),即进程不是直接访问内存的实际物理地址,而是通过内核为进程设置好内存,使得进
程看起来可以使用整个系统的内存。当进程访问内存的时候,MMU 截获访问请求,然后通过内
存映射表将要访问的内存地址转换为实际的物理地址。内核不断初始化、维护和更新这个地址映
射表。例如:在上下文切换时,内核将内存映射表从移出进程转给移入进程使用。
注解:内存地址映射表通过页面表(page table)来实现。
关于内存性能,我们将在第 8 章详细介绍。
除了传统的系统调用,内核还为用户进程提供其他很多功能,最为常见的是:虚拟设备。虚拟设
备对于用户进程而言是物理设备,但是其实它们都是通过软件实现的。因此从技术角度来说,它
们并不需要存在于内核中,但是实际上它们很多
都存在于内核中。例如:内核的随机数生成器(/dev/random)这样的虚拟设备,如果由用户进程来
实现难度要大很多。
1.4 用户空间
前面提到过,内核分配给用户进程的内存我们称为用户空间。因为一个进程简单说就是内存中的
一个状态。用户空间也可以指所有用户进程占用的所有内存。(userland)
Linux 中大部分的操作都发生在用户空间中。虽然所有进程从内核的角度都是一样的,但是实际
上它们执行的是不同的任务。相对于系统组件,用户进程存在于一个基础服务层中。图例 1-3,
最底层是基础服务层,工具服务在中间,用户使用的应用程序在最上层。图例 1-3 是一个简化版
本,你可以看到顶层距离用户最近(如:用户接口和 Web 浏览器)。中间一层中有邮件服务器这
样的组件,供 Web 浏览器使用。最下层的是一些更小的服务组件。
最下层通常是由一些小的组件组成,它们比较精巧,专注完成某一个特定功能。中间层的组件比
较大一些,如:邮件,打印和数据库服务。顶层组件完成用户交互和复杂的功能。组件之间也可
以相互调用。如果组件 A 调用了组件 B 的功能,我们可以视为组件 AB 在同一层级,或者 B 的层
级在 A 之下。
图示 1-3 只是一个粗略图,实际上用户空间里没有很明显的界限。例如:许多的应用程序和服务
会将系统调试信息写入日志,大部分程序使用标准的 syslog 服务来完成,但也有一些程序是自己
实现日志功能。
此外,很多用户空间组件比较难分类,象 Web 服务器和数据库服务器这样的服务组件你可以认为
它们是高级别组件,因为它们复杂度很高。然而,用户应用程序也会经常调用它们的功能,所以
你也可以将它们归入中级别组件。
1.5 用户
Linux 内核支持用户这一 Unix 的传统概念。一个用户代表一个实体,它有权限运行用户进程,对
文件拥有所有权。每个用户都有一个用户名,如:billyjoe。然而内核是通过用户 ID 来管理用户
的,用户 ID 是一串数字标识。(详见第 7 章)
用户机制主要用于权限管理。每一个用户进程都有一个用户作为所有者,我们称其为以该用户运
行的进程。在特定限制条件下,用户可以终止和改变他拥有的进程的行为。但是对其他用户的进
程无权干预。此外,用户可以决定是否将属于自己的文件和其他用户共享。
Linux 操作系统的用户包括系统自带用户和真实用户。详情见第 3 章。其中最关键的用户是
root。root 用户不受前面提到的种种权限的限制,它可以终止其他用户的进程,读取系统中的任
何文件。因此 root 也被称作超级用户。通常 Unix 的系统管理员拥有超级用户权限。
注解:使用 root 权限进行操作是一件很危险的事情,因为用户拥有最高权限,身份难以识别,如
果出错很难恢复。因此,系统设计者通常尽量避免使用 root 权限。而且,root 用户虽然权限很
高,但是还是运行在用户模式中,而非内核模式。
1.6 前瞻
到目前为止你对 Linux 系统的组成应该有了一个大致的了解。用户和用户进程交互,内核管理进
程和硬件系统。内核和进程都在内存中运行。
有了这些基础知识,如果想要了解更多的细节,你需要做一些实际的操作。下一章你会了解到一
些用户空间的基础知识,还有本章没有提及的永久存储(硬盘,文件等),就是存放应用程序和
数据的地方。
第二章 基础命令和目录结构
本章介绍了 Unix 系统的命令和工具,它们在整本书中经常会被使用到。也许你已经对这些基本知
识有所了解,不过我还是建议你花一些时间再浏览一遍,特别是 2.19 节关于目录结构部分。
你也许会问,为什么要介绍 Unix 命令?这本书不是有关 Linxu 的吗?一点没错,Linux 其实是
Unix 的一个变种,它的本质还是 Unix。Unix 这个词在本章中出现的频率甚至高于 Linux,并且你
可以将本章的知识直接应用到其他基于 Unix 的操作系统,如:Solaris 和 BSD。我们尽量再本章
避免介绍过多的只针对 Linux 的内容,一方面可以让你多了解一些其他基于的 Unix 系统,另一方
面也因为那些只针对 Linux 适用的扩展功能往往不太稳定。解了核心的通用命令行能够让你更快
地熟悉任何新的基于 Unix 的操作系统。
注解:Unix 初学者可以看这本书 The Linux Command Line (No Starch Press, 2012), UNIX for
the Impatient (Addison-Wesley Professional, 1995), 以及 Learning the UNIX Operating System,
5th edition (O'Reilly, 2001)。
2.1 The Bourne Shell: /bin/sh
The shell(命令行界面)是 Unix 操作系统中最为重要的部分之一。Shell 是一个应用程序,它运行
命令行,就像用户输入的那些命令。同时它为 Unix 程序员提供了一个编程环境,在这里 Unix 程
序员可以将一些通用的任务分解为一些小的组件,然后使用 shell 来管理和组织它们。
Unix 操作系统中很多重要的部分其实是 shell script(命令行脚本),它们是包含了一系列 shell 命令
的文本文件。如果你曾经使用过 MS-DOS,你可以将 shell script 理解为功能很强大的.bat 批处理
文件。我们将在第 11 章全面详细地介绍命令行脚本。
在你阅读这本书并且不断练习的过程中,你将会越来越熟练地使用命令行界面运行各种命令。它
的优点之一是,一旦你出现了误操作,你能够很容易地知道哪里出错了,然后改正。
命令行界面有很多种,但是它们都是基于 Bourne shell(/bin/sh),它是在贝尔实验室开发的标准命
令行界面,运行在早期的 Unix 系统上。所有基于 Unix 的操作系统都需要 Bourne shell。
Linux 使用了一个增强版本的 Bourne shell,我们叫做 bash 或者 Bourne-again shell。Bash 是大
部分 Linux 系统的默认 shell,通常/bin/sh 链接到 bash。你可以使用 bash 来运行本书的实例。
注解:你的 Unix 系统管理员为你设置帐号的时候,可能默认的 shell 并不是 bash,你可以请他为
你更改默认 shell。