• 1. Linux基础教程(1) 操作系统基础清华大学计算机基础教育课程系列教材 汤荷美 董渊 李莉 程志锐 编著
  • 2. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 3. 总 目 录第1部分 Linux操作系统 第1章 操作系统概述 第2章 处理机管理 第3章 存储管理 第4章 调度 第5章 设备 第6章 文件系统
  • 4. 第2部分 操作系统命令及shell编程 第7章 Linux基本命令 第8章 使用vi编辑文件 第9章 shell编程 第3部分 系 统 管 理 第10章 Linux系统软件的获取和安装 第11章 账号管理 第12章 文件系统管理 第13章 TCP/IP网络管理 第14章 备份与恢复 第15章 XWindow及Genie应用程序
  • 5. 第1部分 Linux操作系统 第1章 操作系统概述1.1 操作系统简介 1.2 操作系统接口 1.3 操作系统功能 1.4 操作系统结构 1.5 Linux操作系统介绍 1.6 Linux的内核特征 1.7 Linux的发展及展望 1.8 小结 习题
  • 6. 操作系统是计算机系统的基本系统软件。软件系统中操作系统是所有软件的核心。操作系统负责控制、管理计算机的所有软件、硬件资源,是惟一直接和硬件系统打交道的软件,是整个软件系统的基础部分,同时还为计算机用户提供良好的界面。因此,操作系统直接面对所有硬件、软件和用户,它是协调计算机各组成部分之间、人机之间关系的重要软件系统。
  • 7. Linux是在日益普及的Internet上迅速形成和不断完善的操作系统。Linux操作系统高效、稳定,适应多种硬件平台,而最具有魅力的是它遵循GPL(GNU General Public License, GNU通用公共许可证,见附录),整个系统的源代码可以自由获取,并且在GPL许可的范围内自由修改、传播,这就为学习、应用、开发操作系统及其他软件提供了良好的基础和较高的起点。 本章首先介绍操作系统的概念、功能及其结构,接着介绍Linux系统的基本特征、发展现状,并以此为基础,讨论现代操作系统的一般特点和发展趋势。
  • 8. 1.1 操作系统简介 1.1.1 操作系统概念 一种非形式的定义如下:操作系统是计算机系统中的一个系统软件,它是这样一些程序模块的集合——它们管理和控制计算机系统中的硬件和软件资源,合理地组织计算机工作流程,以便有效地利用这些资源为用户提供一个功能强大、使用方便和可扩展的工作环境,从而在计算机与用户之间起到接口作用。
  • 9. 普通用户使用操作系统,是把操作系统当作一个资源管理者,通过系统提供的系统命令和界面操作等工具,以某种易于理解的方式完成系统管理功能,有效地控制各种硬件资源,组织自己的数据,完成自己的工作并和其他人共享资源。 对于程序员来讲,操作系统提供了一个与计算机硬件等价的扩展或虚拟的计算平台。操作系统提供给程序员的工具除了系统命令、界面操作之外,还有系统调用,系统调用抽象了许多硬件细节,程序可以以某种统一的方式进行数据处理,程序员可以避开许多具体的硬件细节,提高程序开发效率,改善程序移植特性。
  • 10. 整个计算机系统可以认为是按照一定规则分层构建的,我们可以使用图1.1来示意性地描述这种层次结构。 图1.1 计算机系统层次结构示意图
  • 11. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 12. 1.1.2 操作系统发展简介 操作系统是随着计算机硬件的发展,围绕着如何提高计算机系统资源的利用率和改善用户界面的友好性而形成,发展和不断成熟完善的。 随着计算机硬件的发展,计算机的计算速度越来越快,其高速的数据处理与低速的手工操作之间的矛盾日益突出,传统的手工操作是系统的最大制约因素,昂贵的计算机硬件资源得不到有效的利用。一个重要的技术是批处理,专门的操作人员把用户提交的任务按照一定的类别、顺序组织起来,形成作业序列,这些作业成批地在专门的监督程序控制之下自动执行。这里的监督程序就是操作系统的雏形。
  • 13. 最初的批处理系统中,计算机内存中仍然只有一个程序在运行,总体系统的效率仍然没有发挥出来。解决这个问题的措施称为多道技术。多道程序设计技术使得在内存中有多个程序,保证系统的处理器总是处于工作状态,极大地提高了系统的利用率。 多道技术开始使用在批处理系统中,称为多道批处理系统,这样的系统效率高,但是,在脱机批处理情况下,高效带来的问题是用户对自己作业的控制程度降低。针对这个问题的方案是分时技术。分时系统把处理机的运行时间分成时间片,按照时间片轮流把处理机分配给每一个联机用户。由于每一个时间片很短,宏观上来看,所有用户同时操作计算机,各自独立控制自己的作业。
  • 14. 与分时系统相对应,还有一种实时(real time)操作系统,控制计算机对外来信息进行快速处理,要求系统在允许的时间范围之内做出响应。 同时具有多道批处理、分时、实时处理功能,或者其中两种以上功能的系统,称为通用操作系统。Linux操作系统就是具有内嵌网络功能的多用户分时系统。它兼有多道批处理和分时处理功能,是一个典型的通用处理系统。 一方面强调分布式计算和处理,另一方面强调物理上跨越不同的主机系统、逻辑上紧密耦合构成统一完整的操作系统平台,这样的系统就是分布式操作系统(distributed operating system)。这是当前操作系统发展的一个方向。
  • 15. 当前,计算机微型化和专业化趋势已成事实。这两种发展趋势都产生了一个共同的需求,即嵌入式软件。嵌入式软件也需要操作系统平台的支持,这样的操作系统就是嵌入式操作系统。嵌入式软件系统的规模小,相应地,其操作系统的规模也小。 嵌入式软件的应用平台之一是各种电器,这样的系统面向普通家庭和个人用户,由于快速发展的网络市场,使得家用电器的市场比传统的计算机市场大很多。因此,嵌入式软件可能成为21世纪信息产业的支柱之一,嵌入式操作系统也必将成为软件厂商争夺的焦点,成为操作系统发展的另一个热门方向。
  • 16. 1.2 操作系统接口 操作系统在整个软件系统中处于中心地位,负责控制、管理计算机的所有软件、硬件资源,它屏蔽了很多具体的硬件细节,对计算机用户提供统一、良好的界面(或称为接口,interface)。本节介绍操作系统的接口界面,下一节主要介绍操作系统的管理功能。在计算机层次结构中,操作系统通过接口向上层用户提供各种服务,而上层用户通过操作系统接口来访问硬件。 操作系统提供的接口可以根据服务对象的不同而划分为两类:一是程序级的接口,提供给程序员使用,即系统调用;二是作业级的接口,提供给用户使用,即操作命令。
  • 17. 1.2.1 程序员级接口 系统调用是一组由操作系统提供的广义指令。应用程序通过系统调用来操纵系统内核中特定的函数, 当应用程序需要进行文件访问、网络传输等操作时,必须通过系统调用来完成。程序员在设计应用程序时,涉及到系统资源,都必须使用系统调用来实现,可以说,系统调用是操作系统提供给程序员的惟一接口。 系统调用可以根据功能划分为不同的类型。熟悉系统调用是一个优秀程序员必备的条件。
  • 18. 1.2.2 用户级接口 操作系统提供给用户使用的接口是操作命令,用户可以使用这些操作命令来组织和控制作业的执行或者管理整个计算机系统。实际上,计算机的操作命令界面是在系统调用的基础上开发而成的。 操作系统发展的主要方向除了提高系统资源利用率之外,就是改善用户界面友好性。 图形用户界面是操纵命令界面发展的一个里程碑。图形用户界面,降低了计算机操作的门槛,千万个家庭成为计算机普及的对象。 现在流行的操作系统一般都同时提供图形和文本用户界面。Linux系统就是如此,文本界面是shell接口,图形界面是XWindow系统。
  • 19. 1.3 操作系统功能 多用户分时系统,按照其功能划分为处理机管理、存储管理、设备管理、信息管理(文件系统管理),对于现代流行的操作系统,还具有完整的网络管理功能。这些管理功能都是由操作系统内核实现的。 1.3.1 处理机管理 作业、进程需要适当的分配、调度,以便协调相互关系,共享有限的处理机资源,这是处理机管理的主要内容。 处理机管理是操作系统管理功能的关键,操作系统功能的一个主要指标即是提高处理机的使用率,让处理机尽可能处于工作状态。
  • 20. 1.3.2 存储管理 存储管理的目标是让有限的物理内存尽可能满足应用程序对内存的需求。存储管理的内容包括内存的扩充、分配、保护等。 操作系统多采用了称为“虚拟内存”的内存管理方式。 内存一般采用部分分配的办法。 通常,内存中总是同时存放了多个正在运行的程序实体,即进程,在运行的过程中,他们之间可能会使用到相同内存位置的内容,这种技术称为内存共享,这样,可以提高内存的利用率。但是,必须要确保各进程所占据的内存的独立和完整性。
  • 21. 1.3.3 设备管理 除了CPU和内存之外,计算机的其他部件都统称为外部设备。这些设备在操作系统的控制下协调工作,共同完成信息的输入、存储和输出任务。 操作系统要对所有的设备进行管理。一方面,让每一个设备尽可能发挥自己的特长,实现与CPU和内存的数据交换,提高外部设备的利用率。另一方面,隐蔽设备操作的具体细节,对用户提供一个统一、友好的设备使用界面。 和处理机及内存相比,外部设备的速度要慢得多,而且性能差别大,类型品种多,因此,设备管理是一项复杂而又重要的工作。
  • 22. 1.3.4 文件系统 操作系统在控制、管理硬件的同时,也必须管理好软件资源。操作系统的文件系统就是针对计算机的软件资源而进行的。文件系统主要提供以下服务: 文件存取, 使每个用户能够对自己的文件进行快速的访问、修改和存储。 文件共享, 指提供某种手段,使存储空间只保存一个副本, 而所有授权用户能够共同访问这些文件。 文件保护, 指提供保护系统资源防止非法使用的手段。
  • 23. 1.3.5 网络管理 计算机的发展已经进入了互联网时代,现在流行的操作系统一般都具有内嵌的网络功能,能够在内核级别控制、管理网络。 操作系统一般都提供网络通信和网络服务等基本功能。内核中网络部分,主要实现网络设备控制和网络协议,因此,网络管理也就集中在通信这部分。
  • 24. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 25. 1.4 操作系统结构 本节简单介绍操作系统的逻辑结构,然后介绍操作系统发展过程中使用过的几种主要的体系结构。 1.4.1 操作系统的逻辑结构 计算机系统可以理解为是分层构造的。 从逻辑关系来理解,操作系统本身也可以用层次结构来描述。可以认为至少有4层,从上到下依次为:面对用户的外部接口,硬件无关的内核部分,与硬件相关的内核部分,面对硬件的外部接口。可以简单地用图1.2来描述。这种层次结构可以看作是操作系统纵向的结构。
  • 26. 图1.2 操作系统逻辑层次示意图 操作系统也可根据不同的管理功能划分为功能模块。 一种简单的理解是,操作系统本身划分为功能模块,而每个模块分层构造,形成一个纵横交错的结构。
  • 27. 1.4.2 操作系统的体系结构 软件的体系结构描述系统各部分软件以及它们相互之间的关系, 是软件内部结构配置的一种抽象描述。软件体系结构定义各部分软件系统的应用界面规范及相互操作和数据通信的协议和限制。体系结构相对稳定、满足应用需求,同时具有适当的可适应性和可扩充性。
  • 28. 1. 模块结构 模块结构是将操作系统内核按照功能划分为一个个单独的模块,模块之间相对独立,只能通过预先规定好的接口方式来调用,它们共享数据,模块是系统设计和实现的基本单位。每一个模块实现一个完整单独的功能,所有模块之间相互调用,共同构成一个完整的系统内核。 模块结构最大的优点是效率高。 模块式结构中,操作系统的逻辑层次关系具体由调用层次关系来体现。这种结构的主要问题一是全局函数使用多,造成访问控制困难;二是结构不够清晰,系统的可理解性、可维护性和可移植性都比较差。
  • 29. 2. 层次结构 层次结构的方法把操作系统内核按照一定的规则划分为一系列相互依赖的层次,每个层次也可以分解为一系列更小的模块,模块负责完成一部分特定的功能,只能与相邻的层次发生直接的联系,所有这些层次的组合,就实现了整个系统。 实际上,层次结构可以理解为一种特殊的模块式结构。 层次结构可以大大方便系统的移植和扩充。 把系统内核划分为严格的层次结构,为了满足有序的层次调用关系,必然要牺牲部分灵活性和系统效率。
  • 30. 3. 对象结构 对象也可以理解为一种特殊的模块,它是由一组数据集以及定义在其上的操作集封装而成。对象结构方法中,操作系统内核按照内核对象实体组织,每个内核对象实体都有自己的数据和操作,对象之间通过消息传递来协调工作。 对象模块具有很强的独立性,因此也具有很好的复用性能。 对象模块可以方便有效地控制内部数据的访问属性,充分地隐藏信息,达到资源保护的目的。 采用对象结构,系统的开发难度降低,具有良好的扩展性和移植性,同时有较好的安全功能。 对象结构操作系统内核的一个严重问题是效率低。,
  • 31. Linux内核基本属于模块结构,而MS-DOS系统内核采用的是层次结构,Windows NT/2000及Solaris则是典型的对象结构。 操作系统内核按照其运行的情况可以分为:宏内核与微内核。前者也称为单内核,Linux系统属于单内核类型。对象结构的系统内核通常是微内核,例如,Windows NT/2000系统就是微内核。
  • 32. 1.5 Linux操作系统介绍 Linux系统有两种不同的含义。从技术角度,Linux指的是由Linus Torvalds维护的开放源代码UNIX类操作系统的内核。然而,目前大多数人用它来表示以Linux内核为基础的整个操作系统。从这种意义讲,Linux指的是开放源代码的,包含内核、系统工具、完整的开发环境和应用的UNIX类操作系统。
  • 33. 1.5.1 Linux——自由操作系统 Linux是一个UNIX操作系统的克隆,可以免费使用,遵循GPL声明,可以自由修改和传播。Linux包含了人们希望操作系统拥有的所有功能特性,这些功能包括真正的多任务、虚拟内存、世界上最快的TCP/IP驱动程序、共享库和多用户支持。 Linux现在是个人计算机和工作站上的UNIX类操作系统。它不仅继承了UNIX的特征,而且在许多方面超过了UNIX。作为UNIX类操作系统,它具有下列基本特征:
  • 34. 是真正的多用户、多任务操作系统; 是符合POSIX标准的系统; 提供具有内置安全措施的分层的文件系统; 提供shell命令解释程序和编程语言; 提供强大的管理功能,包括远程管理功能; 具有内核的编程接口; 具有图形用户接口; 具有大量有用的实用程序和通信、联网工具; 具有面向屏幕的编缉软件。
  • 35. 大量的高级程序设计语言已移植到Linux系统上,因而它是理想的应用软件开发平台,而且,在Linux系统下开发的应用程序具有很好的可移植性。同时,Linux还有许多独到之处: (1) 它的源代码几乎全部都是开放的。 (2) 它可以运行在许多硬件平台上。 (3) 它不仅可以运行许多自由发布的应用软件,还可以运行许多商品化的应用软件。 (4) 强大的网络功能。 Linux系统的另一特征是它能充分发挥硬件的功能,因而它比其他操作系统的运行效率更高。 因此,Linux将有广泛的应用前景。
  • 36. 1.5.2 UNIX、GNU与Linux Linux是一种类UNIX系统,二者有相当的渊源,同时,Linux遵循GNU的GPL许可证,是自由软件家族中的一员,因此,要了解Linux,就必须先了解他们三者之间的关系。 1. Linux与UNIX系统 Linux的源头要追溯到最早的UNIX。 UNIX系统正式发表于1974年, 到1975年的第6版中,引入了多道技术。 1980年,Bell实验室公布了VAX11/780系统平台的32位操作系统UNIX32V。
  • 37. 一个可以运行UNIX程序的系统就是UNIX。 经过多年发展,UNIX从实验室走出来并成为了操作系统的主流。直到今天,UNIX系统以其稳定、高效的性能在服务器高端市场中依然占有绝对优势。 很多公司也开发了用于PC的UNIX。 UNIX是一个简单却非常优秀的操作系统模型。Linux系统最初以UNIX为原型,以实现POSIX标准作为其目标,到2000年为止,Linux核心从0.01版发展为2.4版。Linux具有稳定高效的处理性能,拥有稳定庞大的用户群体,得到众多厂商有力的支持,成为操作系统发展的热点。Linux在低端服务器市场上已经对Windows NT/2000造成了极大的压力。
  • 38. 2. 自由软件运动与Linux Linux只是自由软件家族中的一员,是其中最具影响的成员之一。 在计算机工业发展的初期,软件只是硬件的附属品。但是,公司很快认识到软件的价值,对软件实施了版权控制,并限制源代码的发布。 Richard Stallman在其他人的协作下创作了通用公共许可证(General Public License,GPL)。GPL保证任何人有共享和修改自由软件的自由,任何人有权取得、修改和重新发布自由软件的源代码,并且规定在不增加附加费用的条件下得到源代码。
  • 39. 3. Linux的历史 Linux可以说完全是一个互联网时代的产物,它是在互联网上产生、发展和不断壮大起来的。 Linus在自己的PC上,利用Tanenbaum教授自行设计的微型UNIX操作系统MINIX为开发平台,开发了属于他自己的第一个程序。 Linus 说刚开始的时候他根本没有想到要编写一个操作系统内核。 “于是我又不得不写一个磁盘驱动程序,然后是一个文件系统。而一旦当你有了任务切换器、文件系统和设备驱动程序之后,你当然就拥有了一个UNIX”或者至少是它的一个内核。Linux就以这样一种极其古怪但也极其自然的方式问世了。
  • 40. Linus并没有在 MINIX 新闻组中公布它。他只是在赫尔辛基技术大学的一台 FTP 服务器上发了一则消息,说用户可以下载Linux的公开版本。 到1992年1月止,全世界大约只有100个左右的人在使用Linux。 1993 年,Linus 的第一个“产品”版Linux 1.0问世的时候,是按完全自由发行版权进行发行的。 Linux与GPL的结合,使许多软件开发人员相信这是一个有前途的项目,开始参与内核的开发工作,并将GNU项目的C库、gcc、Emacs、bash等很快移植到Linux内核上来。
  • 41. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 42. 商业软件公司的加盟也使大多数 Linux 的普通用户吃了定心丸。Linux从一开始就主要是在一些软件行业中的高手之间流行的,并且很快就在全球范围内集结了一大批职业的和业余的技术专家,形成了一个数量庞大而且非常热心的支持者群体。他们能够通过网络很快地响应使用者所遇到的任何问题。 1997 年,Linux支持者群体在众多的软件公司中一举胜出,荣获了美国《InfoWorld》杂志的最佳技术支持奖,而这一奖项原本只是为商业公司而设立的。Linux核心的版本发展情况见表1.1。该表摘自参考文献[2],表中最后一项,程序行数(Lines of Code,LOC)包含了Linux可应用于如x86、PPC、SPARC等所有平台的程序代码。
  • 43. 表1.1 Linux核心发展情况(截止1998年) 年 份 使用者数量 版 本大小(LOC) 1991 1 0.01 10k 1992 1k 0.96 40k 1993 20k 0.99 100k 1994 100k 1.0 170k 1995 500k 1.2 250k 1996 1.5M 2.0 400k 1997 3.5M 2.1 800k 1998 7.5M 2.1.110 1.5M
  • 44. 当Linux走向成熟时,一些人开始建立软件包来简化新用户安装和使用Linux的方法。这些软件包称为Linux发布或Linux发行版本。在早期众多的Linux发行版本中,最有影响的要数Slackware发布。Linux文档项目(LDP)是围绕Slackware发布写成的。目前,Red Hat发行版本的安装更容易,应用软件更多,已成为最流行的Linux发行版本,2000年秋天已经发行了7.0版本;而Caldera则致力于Linux的商业应用,它的发展速度也很快。中文化的Linux发行版本也有很多,国内自主建立的如BluePoint Linux、Flag Linux、 Xterm Linux以及美国的XLinux、TurboLinux等。
  • 45. 每种发行版本都有各自的优点和弱点,但它们都提供相对完整的应用软件及帮助文档,都使用相同的内核和开发工具,大家都使用同一个名称——Linux系统。
  • 46. 1.6 Linux的内核特征 Linux操作系统的核心稳定而高效,以独占的方式执行最底层任务,保证其他程序的正常运行。它是整个系统的核心,具有独特的性质。本节试图从操作系统接口、功能及内核结构等几个方面来展示Linux核心的特征。 1.6.1 接口特色 按照POSIX标准,一个可以运行UNIX程序的系统就是UNIX。Linux系统提供和一般UNIX系统相同的标准界面,包括程序级的和用户级的,因此也是一个UNIX系统,一般,大家称之为类UNIX系统,以区别于其他传统意义上的UNIX系统。
  • 47. 在程序级,Linux系统提供标准的UNIX函数库,一个在Linux下开发的应用程序,可以几乎不经过任何改动就可以在其他UNIX系统下编译执行,完成同样的功能。 Linux系统对用户同时提供图形和文本用户界面,文本界面是shell接口,图形界面是XWindow系统。UNIX下的基本命令,在Linux下功能和使用方式都完全相同。而最早在UNIX平台开发的图形用户界面XWindow系统,在Linux系统下运行良好并可以展示与其他版本UNIX系统下相同甚至更好的效果。
  • 48. 更为可喜的是,在XWindow系统基础上,自由软件开发者们为Linux开发了不少种类的桌面系统,在这样的环境下,用户几乎可以不再需要传统的文本用户界面,所有的操作都可以通过鼠标点击来完成。这样的系统有方便快捷的KDE(K Desktop Environment),基于CORBA组件技术,具有图形功能的GNOME(GNU’s Network Object Model Environment)等等,它们都遵循GPL,都处在高速发展阶段,相信他们的功能会更加完善。 桌面系统的发展,基于桌面系统的办公、家用软件的发展,将会使Linux操作系统的用户界面更加友好,Linux系统针对办公用户及普通家庭的普及工作也将具有更明显的竞争力和更美好的前景。
  • 49. 1.6.2 功能特色 Linux核心最早运行在Intel 80386系列PC机上,现在,它也可以运行在Apple系列、DEC Alpha系列、MIPS和Motorola 68000系列的计算机上,同时,一些改进的嵌入式Linux核心还可以运行于手机、家电等设备上。从Linux 2.0开始,它不仅支持单处理器的机器,还能支持对称多处理器(SMP)的机器,实现真正的多任务工作。 Linux系统可以支持多种硬件设备。Linux系统下的驱动程序开发和Windows系统相比要简单得多。最初的硬件设备驱动程序,都是由自由软件开发者们提供的,随着Linux系统的普及,越来越多的硬件
  • 50. 厂商也开始提供设备驱动,这对于广大使用者无疑是又一个好消息。 Linux采用多级分页的存储管理模式,具体的技术特征将在后面介绍。 Linux自身使用的专用的文件系统为Ext2,可以提供方便有效的文件共享及保护机制。同时,它可以通过虚拟文件系统的技术,支持包括微软系列操作系统所使用的Fat16、Fat32和NTFS等文件系统在内的几十种现有的文件系统。 Linux系统具有内置的TCP/IP协议栈,可以提供各种高效的网络功能,包括基本的进程间通讯、网络文件服务等。
  • 51. 1.6.3 结构特征 Linux内核基本采用模块结构,单内核模式,这使得系统具有很高的运行效率,但系统的可扩展性及可移植性受到一定的影响。为了解决这个问题,Linux使用了附加模块技术。利用模块技术,可以方便地在内核中添加新的组件或卸载不再需要的内核组件,而且这种装载和卸载可以动态进行。 内核模块的引入也带来了对系统性能、内存利用和系统稳定性的一些影响,可动态装卸的模块需要系统增加额外的资源来记录、管理,而装入的内核模块和其他内核部分一样,具有相同的访问权限,差的内核模块会导致系统不稳定甚至崩溃,一些恶意的内核模块可能对系统安全造成极大的威胁。
  • 52. 总的来讲,Linux内核基本采用模块式结构构造,同时加入动态的模块技术,在追求系统整体效率的同时,实现了内核的动态可伸缩性。这样的结构,给系统移植带来一定的负面影响,但是,在广大自由软件爱好者们不懈的努力下,Linux系统仍然不断地推出支持新硬件平台的版本,Linux可以运行的硬件平台超过任何一种商业系统,具有较好的平台适应性。
  • 53. 1.7 Linux的发展及展望 1.7.1 开发模式 自由软件的开发模式不同于以往任何一种软件开发模式。软件工程的发展,实现了软件的工程化生产——在经过详细的需求分析之后,进入设计阶段,然后是实现、测试等等,整个过程有严格的工作流程、时间限制和质量控制,程序员在整个生产过程中的作用,相当于传统工厂里流水线上的工人,只是按照“图纸”完成某个零部件加工而已,这样的开发模式强调的是统一规划,集中管理。
  • 54. 一大批分布于世界各地的软件爱好者,以互联网为纽带,通过BBS、新闻组及电子邮件等现代通讯方式,同时参与一个软件开发项目。一个初步工作的软件雏形首先发布出来,然后大家同时开始工作,分别结合自己的实际经验和需要,寻找软件中的漏洞,提出改进意见,发布在互联网上,很快,另外的人也发现了漏洞,接着,有人又提出了改进方案,给出了补丁,经过这些人分头修整,这个软件好像滚雪球一样,以很快的速度不断完善。在这样的开发模式中,程序员是独立的实体,他们大多是用业余时间来为自由软件服务的,没有工作任务的压力,他们创作性工作带来的成就感是他们最大的动力。这样的开发模式称为“巴扎”(Bazaar)模式
  • 55. 自由软件的出现,改变了传统的以公司为主体的封闭的软件开发模式。采用了开放和协作的开发模式,无偿提供源代码,容许任何人取得、修改和重新发布自由软件的源代码。这种开发模式激发了世界各地的软件开发人员的积极性和创造热情,大量软件开发人员投入到了自由软件的开发中。软件开发人员的集体智慧得到充分发挥,大大减少了不必要的重复劳动,并使自由软件的漏洞能得到及时发现和克服。任何一家公司都不可能投入如此强大的人力去开发和检验商品化软件。这种开发模式使自由软件具有强大的生命力。
  • 56. 1.7.2 内核版本 为了确保看似无序的市集开发过程能够有序地进行,自由软件一般都必须采取强有力的版本控制措施。 Linux内核采用的是双树系统。一棵树是稳定树,主要用于发行;另一棵树是非稳定树或者开发树,用于产品开发、改进。 一些新特性、实验性改进等首先在开发树中进行。如果在开发树中所做的改进也可以应用于稳定树,那么在开发树中经过测试以后,就在稳定树中进行相同的改进。按照Linus的观点,一旦开发树经过了足够的发展,开发树就会成为新的稳定树,如此周而复始地进行下去。
  • 57. 源代码版本序号的形式为x.y.z。对于稳定树来说,y是偶数;对于开发树来说,y是比相应稳定树大一的奇数。截止到2000年10月,最新的稳定内核版本号是2.4.test9。 这种开发会比常规惯例要快,因为每一版本所包含的改变比以前更少了,内核开发人员只需花很短的时间就能够完成一个实验开发周期。 当今,Linus率领分布在世界各地的Linux内核开发队伍正在完善他们的作品。Linux内核2.x版本充分显示了Linux开发队伍的非凡的创造力和市集开发模式的价值。Linux核心开发者的名单记录在文件/usr/src/linux/CREDITS中。
  • 58. 事实上,UNIX开始发展时,也采用了类似的开发 模式。这种开发模式使得UNIX的安全漏洞比其他操作系统解决得更彻底。从充分发挥开发人员的集体智慧这一点看,采用这种开发模式无疑是一大进步。 1.7.3 国内应用状况 随着Linux核心的不断成熟,各种性能稳定、安装方便、支持多语种的发行版本被广泛地使用。Linux得到广大硬件、整机厂商和应用程序厂商的大力支持,这一切,都使得Linux这个年轻的系统充满了希望。
  • 59. 由于多种原因,Linux在国内的推广比国外晚了几年,近年来有更多的软件爱好者开始了Linux的学习、应用和研究开发,同时,许多大学还把它作为操作系统课程实验的内容,这些都为Linux在中国的推广使用奠定了基础。 Linux的使用开始于国内的高校和科研单位,最初大家在各地的电子公告牌上研论问题,随着讨论的深入,他们开始成立各种民间组织,建立自己的主服务器。爱好者们在这些地方,下载软件,自由地讨论Linux方面的问题,寻找志同道合者切磋,方便而高效地交流信息。这为Linux的进一步推广和本地化创造了良好的环境。
  • 60. 目前国内较有影响的推广项目是1997年6月17日在国家经济信息中心网上建立的自由软件协会站点(图1.3),其网址是:http://freesoft.cei.gov.cn/freesoft.html,这既是一个大型自由软件库,也是一个自由软件应用的示范项目。整个系统建立在Linux基础上,提供WWW、FTP、DNS、News和邮件服务,从开通到2000年12月,访问人数已超过70万人次。 同时,国内也出现了多家Linux发行商,推出多种汉化的Linux版本,如BluePoint、Xterm Linux、Flag Linux等等,同时也提供系统集成、技术支持等服务。
  • 61. 总的来讲,国内Linux发展还处于一个比较低的层次,初级入门用户很多,实际应用用户少、而从事自由软件开发的人就更少了。 1.7.4 发展方向 Linux内核本身的发展方向主要是硬件支持、嵌入系统和分布式系统这三个方面。 提供更多高性能的硬件驱动程序,让更新、更好的硬件迅速在Linux系统下工作,是Linux普及和广泛应用的基础。
  • 62. 随着以计算技术、通信技术为主体的信息技术的快速发展和Internet的广泛应用,嵌入式软件成为软件业的新热点。面对如此巨大的电子产品市场和潜在用户群,嵌入式软件的应用前景十分广阔,而Linux系统本身的开放特性以及稳定的性能,都比较适合作为开发嵌入系统的原型,国内外都有这样的研究项目,也有相当成功的事例。 分布系统是当前操作系统发展的另一个重要领域。以Linux内核为基础,按照自由软件开发模式,发展高性能的自由分布操作系统,是操作系统发展的必然趋势。
  • 63. 此外,Linux上的桌面系统、应用软件,尤其是软件开发工具也是Linux发展的重要方面。桌面系统直接关系到Linux界面的友好性,易用性。应用软件关系到系统的可用性,而在自由软件开发模式当中引入软件工程新技术和成功经验,有助于快速开发Linux平台上的应用软件。
  • 64. 1.8小结 本章首先介绍了操作系统的一般概念及发展历史,接着介绍了操作系统的外部接口、管理功能及其内部结构,特别强调了计算机系统层次结构的概念。以此为基础,详细剖析了Linux系统的接口、功能和结构,包括 Linux的发展及其开发模式。
  • 65. 操作系统是计算机系统的基本系统软件,在整个计算机系统中处于核心地位,它是这样一些程序模块的集合——它们管理和控制计算机系统中的硬件和软件资源,合理地组织计算机工作流程,以便有效地利用这些资源为用户提供一个功能强大、使用方便和可扩展的工作环境,从而在计算机与用户之间起到接口作用。
  • 66. Linux是在日益普及的Internet上迅速形成和不断完善的操作系统。Linux操作系统高效、稳定,适应多种硬件平台,支持多种文件系统,它遵循GPL协议,整个系统的源代码可以自由获取,并且在GPL许可的范围内自由修改、传播,这就为学习、应用、开发操作系统及其他软件提供了良好的基础和较高的起点。 学习操作系统一般概念和原理,对于理解、使用和管理Linux系统,开发应用软件以及系统软件,都具有相当重要的意义。
  • 67. 习题 1-1 操作系统的基本功能有哪些? 1-2 从技术的角度讲,Linux是一个什么样的操作系统?你认为它有哪些不足?如何改进? 1-3 阅读通用许可证协议和参考文献[1]、[2],深入了解自由软件的“巴扎”开发模式,你愿意让大家共享你的软件吗?为什么?你认为“巴扎”模式有哪些优点?哪些缺点?缺点如何改进? 1-4 访问Linux核心代码站点http://www.kernel.org ,了解Linux核心发展的最新进展及新增功能。
  • 68. 1-5 访问Internet,了解一个国内的自由软件项目,向大家介绍这个项目的管理及进展情况,给出你对该项目的评价及改进意见。
  • 69. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 70. 第2章 处理机管理2.1 作业 2.2 进程 2.3 线程 2.4 小结 习题
  • 71. 提高处理机(CPU)的使用率,使它尽可能处于工作状态,是操作系统管理功能的主要目标之一。 在Linux系统中,提高处理机使用率的技术措施主要是多道和分时,处理机在进程之间切换,按照一定的规则轮流执行每个进程。对于单个处理机的系统,这些进程宏观上看似并行执行,而微观上来看仍然是串行执行的,这种执行方式被称为并发执行。操作系统通过并发控制机制,对处理机进行分配、调度,在保证每个进程都得到公平合理执行的同时,使系统中的各种资源得到充分的使用。 本章主要围绕处理机管理展开,着重介绍进程的概念,同时也包括相关的两个基本概念:作业和线程。
  • 72. 2.1 作业 作业是用户向计算机系统提交一项工作的基本单位,是用户在一次事务处理或计算过程中要求计算机所做工作的总和。 作业和程序是两个相互联系而又不同的概念。如果一次业务处理可以由某一个程序完成,就是说这个业务处理只要提交这一个程序就够了,这种情况下,这个程序就是一个作业。通常,完成一次业务需要由多个程序协同完成,这时,多个程序、这些程序需要的数据以及必要的作业说明一起构成一个作业。系统通过作业说明书或者作业控制语句(JCL)控制程序和相应的数据执行,完成整个业务处理。
  • 73. 按照对作业的处理方式,可以分为联机、批处理等作业。 Linux系统中的shell提供了操作系统和用户之间的联机命令接口。 Linux的shell同时提供了程序级接口。用户通过提交一个命令或一个命令序列以批处理方式执行特定的操作(详见本书第2部分)。 在Linux分时批处理系统中,也可以根据对作业执行时的响应特征分为前台作业和后台作业。 在多用户系统中,多个用户、不同类型的作业可能同时请求执行,控制和管理这些作业,协调它们之间的关系,就是作业调度,作业调度是处理机调度的一部分。
  • 74. 2.2 进程 计算机内存中同时存放多个相互独立的已经开始运行的程序实体,大家按照某种规则轮流使用处理器,这是现代多道操作系统实现资源共享,提高系统资源利用率的主要方式。描述这些程序实体的概念就是进程。 在多道情况下,每个进程独立地拥有各种必要的资源,占有处理机,独立地运行。在多道系统中,同时存在多个进程,所以当某个进程进入等待状态时,操作系统将把处理机控制权拿过来并交给其他可以运行的进程。进程之间存在着相互制约、相互依赖的约束关系。
  • 75. 一种最糟糕的情况是所有进程都拥有部分资源,同时在等待其他进程拥有的资源,这样,大家都无法运行,进入一种永久等待的状态,这种情况称为死锁,死锁是对系统资源极大的浪费,必须设法避免。 本节着重讨论现代多道操作系统中的核心概念——进程,这是理解操作系统工作原理的基础和关键。首先介绍单个进程的状态、状态转换的条件和控制原语、进程在系统中的静态描述等,接着介绍多个进程之间的约束关系,由此引出进程间通信的概念,通信是协调、解决进程间约束关系的惟一手段,这种约束关系处理不当造成的最严重的后果就是死锁。
  • 76. 2.2.1 进程的概念 进程(process)的概念最早出现在60年代中期,用于多道系统,在Linux系统中,进程也称为任务(task)。简单地讲,进程就是正在运行的程序,更为严谨的表达是,进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。 进程的概念对于理解操作系统有决定性的意义,而真正理解进程,必须了解它的基本性质。 进程是操作系统分配资源和进行调度的独立单位,具有独立性。同时,具有动态性。多道系统中同时存在多个进程,这些进程拥有各自的资源,各自独立地执行,对于单处理机系统,进程宏观上同时运行而微观上是依次执行,这种情况称为并发执行。
  • 77. 1. 进程和程序 进程和程序是一对相互联系的概念。程序是指令的有序集合,是一个静态的概念,描述完成某个功能的一个具体操作过程,而进程是程序针对某一组数据的一次执行过程,更强调动态特征。一个完整的进程,包括程序、执行程序所需要的数据,同时还必须包括记录进程状态的数据资料。 在多道分时操作系统中,按照时间片轮流在各个进程间切换。对于单处理器系统,每一个时刻只能有一个进程在执行,当分配给该进程的时间片用完之后,不管该进程运行到什么程度,都必须立即停止,然后让出处理器资源,下一个进程进入执行状态。
  • 78. 让出处理器的进程必须记录好正在运行的状态,包括寄存器、堆栈等各种信息,这些信息保证当处理器下次切换到这个进程的时候,进程能够正确地从上次执行到的位置继续往下执行。 一个程序在处理相同或不同的操作数据时可以同时对应于多个进程。一个进程也可以包含多个程序,某个程序在运行过程中,可能同时会调用到多个其他程序,这些具有调用关系的多个程序共同构成一次完整的运行活动,即一个完整的进程。
  • 79. 举一个直观的例子。我们在Linux系统下使用编辑器vi进行编辑,同时打开多个窗口,编辑多个不同名称的文件,vi编辑器是一个可执行程序,不同的文件就是不同的操作数据,而对应于这些文件同时打开的每一个编辑窗口就对应着一个进程,每一个进程都处于不同的状态。 如果说程序是提供计算机操作的一组工作流程的话,进程就是具体的工作过程,按照同样的工作流程,针对不同的原料,可以同时开始多个工作过程,得到多种不同的成品。这种工作流程和工作过程的关系就可以类比为程序和进程的关系。
  • 80. 2. 进程和作业 作业是用户向计算机系统提交一项工作的基本单位,是用户在一次事务处理或计算过程中要求计算机所做工作的总和。进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是操作系统分配资源和进行调度的基本单位。 作业是描述用户向系统提交工作任务的实体单位,而进程是系统完成工作任务时程序执行的实体单位。从这个角度讲,他们处于不同的层次,作业描述用户和操作系统之间的任务委托关系,而进程描述操作系统内部任务的具体执行过程。一个用户的任务,即作业,由用户提交给系统,必须以进程的形式具体完成。
  • 81. 对于批处理系统,通常,作业放在外存中专门的作业队列中等待进入内存执行,要经过一次宏观调度,由外存进入内存,以进程的形式运行。而对于UNIX/Linux这样的分时系统,没有宏观调度,作业不经过调度,直接进入内存,以进程的形式开始运行。任何一个进程,都存在于内存中,并且是已经开始运行的动态实体。
  • 82. 2.2.2 进程描述 我们知道,进程是一个动态的概念,描述程序的一次运行活动。它存在于系统的内存中,是操作系统可感知、可控制的动态实体,是系统分配各种资源、进行调度的基本单位。 1. 进程控制块 现在我们来讨论进程在内存中的静态存在方式。在多道系统中,处理机在多个进程之间来回切换,每个进程都会在暂停、运行这两种状态之间来回转换。当一个进程在处理机切换过来重新进入运行状态时,它必须严格精确地接着上次运行的位置继续进行,进程的静态描述可以保持切换现场,确保准确衔接,保证进程调度的实现,顺利完成程序所规定任务。
  • 83. 进程切换现场称为进程上下文(context),包含了一个进程所具有的全部信息,一般包括:进程控制块(Process Control Block,PCB)、有关程序段和相应的数据集,具体组成见图2.1。程序段是某个进程执行的相关指令集合,和静态的程序段有明确的对应关系,相应数据集是这个程序段正在操作的那部分数据,PCB是记录进程各种状态的数据体,PCB是操作系统管理感知、控制进程的数据实体,通过它,就可以找到进程的程序段和数据集,系统正是通过PCB来控制进程的。一般来讲,PCB记录着进程的所有资料,是全部或部分常驻内存的,PCB记录着程序段和数据集的地址指针,通过这些指针,就可以得到具体的指令和数据。
  • 84. PCB记录了进程的全部控制信息,一般较庞大而复杂,它可以按照功能大概分成四个组成部分:进程描述信息、进程控制信息、进程相关的资源信息和CPU现场保护结构(如图2.1)。 图2.1 进程描述数据关系示意图(进程上下文)
  • 85. 2. Linux的PCB Linux系统的进程控制块PCB用一个称为task-struct的结构体来描述。 (1) 进程描述信息 通过进程描述信息,Linux系统可以惟一地确定某一个进程的基本情况,可以了解该进程所属的用户及用户组等信息,同时还能确定这个进程与所有其他进程之间的关系。这些描述信息包括:进程号、用户和组标识以及描述进程家族关系的连接信息。
  • 86. ① 进程号(pid, process identifier) Linux系统为每一个进程分配一个标识号,通过这个标识号识别、控制、调度这个进程,别的进程也通过这个标识号来识别这个进程并与之通信,用户也可以使用操作命令或系统调用通过标识号来控制该进程。 ② 用户和组标识(user and group identifier) Linux系统中有四类不同的用户和组标识,主要用来控制进程对系统文件的访问权限,实现系统资源的安全访问。 Linux使用组将文件和目录的访问特权授予一组用户,一个进程可以同时属于多个组,这些组都被放在进程的task-struct中的group数组中。
  • 87. ③ 连接信息(Links) Linux系统中的进程之间形成树状的家族关系,连接信息记录某个进程的父进程、兄弟进程(具有相同父进程的进程)以及子进程的信息,描述一个进程在整个家族系统中的具体位置。 (2) 进程控制信息 进程控制信息记录了进程的当前状态、调度信息、记时和时间信息以及进程间通信信息,是系统确定进程的状态、了解进程之间的关系、进行进程调度的主要依据。 ① 进程当前状态 进程的生命周期中,总是不停地在各种状态之间转换,有关进程的状态及转换规则,在下一小节讨论。
  • 88. ② 调度信息 系统的调度程序利用这部分信息决定哪一个进程应该运行,包括优先级、实时优先级、计数器和调度策略。 ③ 记时信息 包括时间和定时器,给出进程占有和利用CPU的情况,是调度的依据,也是进行统计、分析以及记费的依据。 ④ 通信信息 多个进程之间通信的各种信息也记录在PCB中。Linux支持典型的UNIX进程间通信机制——信号、管道,也支持System Ⅴ通信机制——共享内存、信号量和消息队列。
  • 89. (3) 进程资源信息 Linux的PCB中包含大量的系统资源信息,这些信息记录了与该进程有关的存储器的各种地址和资料、文件系统以及打开文件的信息等等。通过这些资料,进程就可以得到运行需要的相关程序段以及必要的数据。 (4) CPU现场信息 进程的静态描述必须保证一个进程在获得处理机并重新进入运行状态时,能够精确地接着上次运行的位置继续进行。相关程序段和数据集以及处理机现场(或处理机状态)都必须保存。处理机(CPU)现场信息一般包括处理机的内部寄存器和堆栈等基本数据。
  • 90. task-struct是Linux系统的进程控制块(PCB),通过对PCB的操作,系统为进程分配资源并进行调度,最终完成进程的创建和撤销。系统利用PCB中的描述信息来标识一个进程,根据PCB中的调度信息决定该进程是否应该运行。如果这个进程要进入运行,首先根据其中的CPU现场信息来恢复运行现场,然后根据资源信息获取对应的程序段和数据集,接着上次的位置开始执行,同时通过PCB中的通信信息和其他进程协同工作。
  • 91. 2.2.3 进程状态及转换 系统通过PCB对进程进行控制,进程不断地在不同的状态之间转换。 1. 进程的基本状态 在分时系统中,一个进程拥有了所需要的全部资源,就可以开始执行,当分配的时间片结束,让出CPU资源,这种只要能够占有CPU就能进入执行的状态称为就绪状态。有时,多个进程之间互相制约,某个进程必须等到某个事件发生(才能够竞争CPU资源,这是等待状态,当等待的事件发生之后,这个进程被唤醒,由等待状态进入就绪状态,直到获得CPU才开始执行。等待状态、就绪状态和执行状态是一个进程所具有的最基本的三种状态,见图2.2。
  • 92. 图2.2 进程基本状态及转换示意图
  • 93. 2. Linux系统进程状态 Linux系统的2.2.16版本进程共有六种状态,包括运行状态、可中断等待状态、不可中断等待状态、僵死状态、暂停状态和交换状态,而在2.4.0版本中取消了交换状态,加入独占状态。 表2.1 Linux系统(2.2.X—2.4.X版本)进程状态表进程状态值说明TASK-RUNNING0运行态TASK-INTERRUPTIBLE1等待态,可中断TASK-UNINTERRUPTIBLE2等待态,不可中断TASK-ZOMBIE4僵死态TASK-STOPPED8暂停态TASK-SWAPPING16交换态(2.4.X版本已取消)TASK-EXCLUSIVE32独占态
  • 94. (1) 运行状态(running) Linux系统中的运行状态实际包含了上述基本状态中的执行和就绪两种状态,进程到底是正在运行还是处于就绪状态准备运行,要靠当前是否占有CPU资源来区分。 (2) 等待状态 Linux系统把基本的等待状态进一步细化为可中断的等待态和不可中断的等待态两种。处于这种状态的进程都在等待某个事件或某个资源,可中断等待状态的进程可以被信号唤醒而进入就绪状态等待调度,而不可中断等待状态的进程是因为硬件资源无法满足,不能被信号唤醒,必须等到所等待的资源得到之后由特定的方式唤醒。
  • 95. (3) 僵死状态(zombie) 由于某些原因进程被终止,这个进程所拥有的内存、文件等资源全部释放之后,还保存着PCB信息,这种占有PCB但已经无法运行的进程就处于僵死状态。 (4) 暂停状态 处于暂停状态的进程,一般都是由运行状态转换而来,等待某种特殊处理。比如处于调试跟踪的程序,每执行到一个断点,就转入暂停状态,等待新的输入信号。 (5) 交换状态 处于交换状态的进程正在执行内存、外存的交换工作。这个状态在2.2.X版本的内核中基本已经不使用,在2.4.X版本中没有这种状态。
  • 96. (6) 独占状态 它应该是等待状态的一种,处于独占状态的进程位于等待队列中,当等待的事件发生时,只有处于这种状态的进程被唤醒,其他处于可中断和不可中断等待状态的进程则继续等待。Linux 2.4引入独占状态后,如果事件发生,只唤醒处于独占状态的那一个进程,这就可以大大提高Apache这类Web应用的效率,使Linux更适合网络服务器的角色。 来看Linux系统进程的状态转换情况。采取一定的简化措施:按照进程是否占有处理机为依据,把进程的运行状态分为执行和就绪两种状态;等待状态统一考虑,不再区分是否可中断,独占状态也作为一种等待状态处理;不涉及交换状态。见图2.3。
  • 97. 图2.3 Linux系统进程状态及转换示意图 图2.3同时也记录了一个进程在整个生命周期的变化过程。从图的左下方开始看,系统在某种特定的情况下,响应某个要求,首先分配各种资源,创建一个新的进程,进程进入就绪队列。
  • 98. 所有的进程必须在就绪之后,才有资格竞争CPU,进入运行状态。这样,进程的整个生命周期中,大致的转换路径总是沿着三个闭合回路进行。 就绪状态和执行状态形成第一个回路。进程进入就绪态,放入可执行队列等待,一旦被调度函数选中,就切换现场,进入运行状态,等自己的时间片耗尽之后,马上保护现场,让出CPU,转入就绪状态,等待新的调度。 执行状态、等待状态和就绪状态形成第二个回路。处于执行状态的进程,有时需要等待某个事件或某种资源的发生,这时,继续占有CPU也无法开展工作,就转入等待状态,CPU由下一个被调度的进程占有。当等待进程所等待的事件发生后,等待进程被唤醒,进入就绪状态。
  • 99. 执行状态、暂停状态和就绪状态构成第三个回路。当接收到某种特殊的信号,比如SIGSTOP(Linux的停止信号)时,处于执行状态的进程放弃CPU,保护现场之后,进入暂停状态,直到获得另外一个特殊的信号才进入就绪状态。 一个处于执行状态的进程调用退出函数exit之后,进程就会进入僵死状态,这种状态下,进程释放了PCB之外的所有系统资源。也就是说,它在系统中只留下这个进程的一个PCB。 僵死进程的父进程通过PCB了解到该进程所处的状态后,采取相应的处理措施,回收PCB,这个进程就完成了它的使命,从僵死走向彻底消亡,上图右上方的虚箭头表示了这种结局。
  • 100. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。
  • 101. 2.2.4 进程控制 进程控制,是指对系统中的全部进程实施有效的管理,使得进程能够及时创建、撤销,正确地完成进程各状态之间的转换,使得多个进程高效率并发执行,达到系统资源高度共享的目的。 进程状态之间的转换转换通常由三种不同的方式控制:进程控制原语、系统核心函数(比如调度)、和外部事件发生(比如中断)。 这里说的所谓原语, 指系统状态下执行的一些具有特定功能的程序段, 这些程序段具有“原子性” ,是执行过程中不可分割的最小单位。用于进程控制的原语有:创建原语、撤销原语、阻塞原语、唤醒原语等。
  • 102. (1) 创建原语 进程创建原语用于建立一个新的进程,这个新进程可以由内核调用进程创建原语建立,也可以由父进程执行进程创建原语生成一个子进程,子进程还可以生成子进程,以形成树形进程家族结构。进程创建原语的主要任务是形成进程的PCB, 因此,调用者必须提供有关的参数,例如进程名、进程优先级、进程正文段起始地址、资源清单等。 (2) 撤销原语 当一个进程完成了指定的任务或由于某种错误导致异常终止时,要撤销这个进程以便释放进程占用的资源。进程撤销原语根据调用者提供的信息,找到指定的进程,回收其占用的资源和PCB。
  • 103. (3) 阻塞原语 当正在运行的进程需要等待某一事件,由自己调用阻塞原语把自己阻塞起来成为等待状态。阻塞原语主要完成保护CPU现场的工作, 即首先中断处理机保存该进程的CPU现场,然后把被阻塞的进程置为等待状态,插入到相应的等待队列,最后转入进程调度程序,从就绪队列中选择一个进程投入运行。 (4) 唤醒原语 当处于等待状态的进程所等待的事件出现时,由发现者进程调用唤醒原语唤醒被阻塞的进程。 进程控制原语由系统执行。同时,操作系统还提供了一些用于进程控制的系统调用和操作命令,用户可以通过程序或者命令的方式控制进程。
  • 104. 2.2.5 进程约束 现代操作系统中,程序并发执行,多个进程各自独立地运行,同时竞争和共享系统中有限的资源,这种竞争与合作构成了系统进程之间的约束关系。每个进程独立地申请和释放系统资源,把申请某一类资源的进程称为该类资源的消费者,把释放同类资源的进程称为该类资源的生产者,就得到描述进程约束关系的一般模型:生产者-消费者问题,也称为有界缓冲区问题。 比较简单的情况,两进程共享一个长度为N(N>0)的有界缓冲区,一个进程Pp往缓冲区中送数据,是生产者,另一个进程Pc从缓冲区中读取数据,是消费者,如图2.4,下面来讨论它们间的约束关系。
  • 105. 图2.4 简单的生产者-消费者问题
  • 106. 首先,生产者进程Pp和消费者进程Pc共享同一个有界缓冲区,对这个缓冲区的操作必须是独占的。这种不允许多个并发进程交叉执行的资源称为临界资源,临界的程序段资源称为临界部分或临界区。临界资源是由于不同并发进程共享某个资源造成的,不可能通过增加资源的方法解决。这种因为共享某一公有资源而引起的在临界资源内不允许并发进程交叉执行的现象,称为进程间的间接约束。 由于对临界资源的共享,而产生了临界区问题。对于有着临界区问题的并行进程之间必须互斥,以保证不会同时进入临界区。
  • 107. 其次,对生产者进程Pp和消费者进程Pc访问共享有界缓冲区的顺序有严格的要求。具体来讲,这种限制为: (1) 消费者进程Pc要接收数据时,有界缓冲区必须至少有一个单元是满的; (2) 生产者进程Pp要发送数据时,有界缓冲区必须至少有一个单元是空的。 这样存在一组相互独立的并发进程,各自的执行结果互为对方的执行条件,从而限制各进程执行速度的过程,称为进程间的直接制约。存在直接制约关系,相互发送消息进行互相合作、互相等待,各自按照一定的速度向前推进的过程称为同步。
  • 108. 消费者进程和生产者进程之间因为共享缓冲区,相互竞争而间接制约,具有互斥关系,同时相互以对方的运行结果为条件而直接制约,也具有同步的关系,是一对同时具有竞争和合作的进程。 在并发系统中,进程之间相互制约,具有同步和互斥是相当普遍的现象。这种进程之间的相互关系,依靠单个进程自身的力量是无法解决的,必须以进程间的相互通信为基础,互相发送信息,才能协调解决。具体的同步、互斥实现方案有很多种,分别基于不同的通信方式。
  • 109. 2.2.6 进程通信 进程间通信是协调解决多个进程之间的约束关系,实现进程共同进展的关键技术,是多道系统中控制进程并发执行必不可少的机制。进程间的通信有两种方式:一是互相发送少量的控制信息,一般只传递一个或者几个字节的数据,进程利用这些简单的信息,实现互斥和同步,控制运行速度,这种简单的通信方式被称为进程间的低级通信;另外一种方式称为进程间的高级通信,基本不涉及进程执行速度控制,用来在进程之间传递大量的信息,由于这种通信方式主要用于交换信息, 因此,在开发本地进程间通信的同时,也为远程进程间的通信,和计算机网络的开发及控制奠定了基础。
  • 110. 1. 进程通信类型 按照通信进程双方的地位,可以把进程通信分为:主从式、会话式、消息或邮箱机制以及共享存储区四种类型。 (1) 主从式 主进程一方在整个通信过程中处于绝对的控制地位,它可以直接控制从进程的动作,自由地使用从进程的资源和数据。 (2) 会话式 一方进程提供服务,另外一方进程在得到服务方的许可之后,可以使用其提供的服务。在通信过程中,双方的连接关系固定,客户进程提出服务请求,服务进程根据情况控制服务的状态和内容。
  • 111. (3) 消息或邮箱机制 通信双方具有平等的地位,和现实生活中的邮件类似。通信双方通过缓冲区或邮箱存放被传送的数据, 不需要建立双方直接的连接关系。申请通信的发起方进程不管接收方进程的状态,把信息直接送入双方共享的缓冲区(或者邮箱)中,接收进程在合适的时机去读取缓冲区(或者邮箱)以接收信息。 (4) 共享存储区 共享存储区通信方式中,通信双方进程共享内存中的一段存储空间,共同操作这个存储区,达到数据共享的目的。通信过程中,数据一直存放在共享存储区中,不需要移动,因此特别适用于大量数据的传递。
  • 112. 2. Linux系统的进程通信 Linux系统提供了多种通信机制,利用这些机制,可以方便地进行进程之间的相互协调,实现进程的互斥和同步。 (1) 信号(signal) 信号属于Linux系统的低级通信,主要用于在进程之间传递控制信号。 信号可以发给一个或多个进程,可以是由某个进程发出,也可以由键盘中断产生,还可以是由shell程序向其子进程发送任务控制命令时产生。进程在某些系统错误环境下也会有信号产生。
  • 113. 除了两个信号外,进程可以忽略这些信号中的绝大部分,这两个信号是引起进程终止执行的SIGSTOP信号和引起进程退出的SIGKILL信号。至于其他信号,进程可以选择处理它们的具体方式。信号没有固有的相对优先级。 并不是系统中每个进程都可以向所有其他进程发送信号,只有核心和超级用户具有此权限。普通进程只能向具有相同uid和gid的进程或者在同一进程组中的进程发送信号。信号是通过设置task-struct结构中signal域里的某一位来产生的。如果进程没有阻塞信号并且处于可中断的等待状态,则可以将其状态改成running,若确认进程还处在运行队列中,就可以通过信号唤醒它。
  • 114. (2) 管道(pipe) 管道是UNIX操作系统传统的进程通信技术。Linux管道通信包括无名管道和有名管道两种,通过文件系统来实现。管道也是一种特殊的文件类型,实际上是通过文件系统的高速缓冲实现的。 两个进程通过管道进行通信时,两个进程分别进行读和写操作,都指向缓冲区中同样的物理单元,一个进程写入数据,另一个进程从缓冲区中读取数据,从而实现信息传递。管道方式只能按照先进先出方式单向传递信息。管道方式可以用来进行大规模的数据传递。
  • 115. (3) SYSTEM Ⅴ进程间通信 信号量、消息队列和共享内存是UNIX/Linux系统常用的通信方式。 消息队列用来在进程之间传递分类的格式化数据,共享内存方式可以使不同进程共同访问一块虚拟存储空间,通过对该存储区的共同操作来实现数据传递,信号量主要用于进程之间的同步控制,通常和共享内存共同使用。 这三种方式在系统中是作为一个整体实现的。 共享内存是这三种方式中通信效率最高的,它在进程的虚拟空间中进行,而且不需要数据的移动也可以实现大规模的数据传递。
  • 116. (4) 套接字(socket) 套接字是用来通过网络实现运行于不同计算机上的进程之间通信的机制。它可以实现数据的双向规模传递,是整个网络通信的基础。具体的原理和实现与网络协议等有关,不做具体的介绍。
  • 117. 2.2.7 死锁 死锁,是指所有并发进程都拥有部分资源,同时都在等待其他进程拥有的资源,而且在得到对方资源之前不会释放自己占有的资源,所有进程都进入永久等待状态而无法运行的情况。死锁是并发进程约束关系处理不当造成的最严重的后果,是对系统资源极大的浪费,必须设法避免。 死锁出现的根本原因是系统资源的有限性。并发进程竞争资源,调度不当,就可能出现死锁的情况,因此必须采取适当的措施来消除死锁。
  • 118. 产生死锁的必要条件有四个:并发进程之间是互斥关系,每个进程必须独占某个系统资源;进程占有的资源在未结束使用之前,不能被强行剥夺,只能由该进程自己释放;进程需要的资源采用部分分配的方式,在等待新资源的同时,继续占有已分配的资源;各占有资源的进程形成环路,每一个进程已获得的资源同时被下一个进程请求。
  • 119. 解决死锁的方案就是破坏死锁产生的必要条件。方法分为预防、回避、检测恢复三种。预防指采取某种策略,控制并发进程对资源的请求,保证死锁的四个必要条件在系统运行的任何时刻都无法满足。避免指系统采取某种算法,对资源使用情况进行预测,使资源分配尽可能合理,避免死锁的发生。这两种方法需要大量的系统开销,而且系统的资源也无法得到充分的利用。因此,一般系统都采取检测恢复的方法,这种方法是在死锁发生之后,根据系统情况,检测死锁发生的位置和原因,使用外力,重新分配资源,破坏死锁发生的条件,系统就可以从死锁状态恢复正常运行,这样的方法只要使用少量的系统资源,尤其是CPU时间就可以排除死锁。
  • 120. 2.3 线程 多道处理系统中,进程是系统调度和资源分配的基本单位,计算机的CPU不停地在不同进程之间切换,进程切换现场称为进程上下文,每一次切换过程,系统都要对换出进程的上下文做详细记录,然后恢复换入进程的上下文。因此,系统的进程管理过程要耗费相当多的系统资源和CPU时间,尤其是对于需要频繁进程切换的任务。 针对进程切换的时间和资源耗费问题,为了减少系统进程切换的时间,提高整个系统的效率,引入了线程的概念。
  • 121. 2.3.1 线程的概念 线程是在一个进程内的基本调度单位。线程可以看作是一个执行流,拥有记录自己状态和运行现场的少量数据(栈段和上下文),但没有单独的代码段和数据段,而是与其他线程共享。 多个线程共享一个进程内部的各种资源,分别按照不同的路径执行,同时线程也是一个基本调度单位, 可以在一个进程内部进行线程切换,现场保护工作量小。一方面通过共享进程的基本资源而减轻系统开销,另一方面提高了现场切换的效率,因此,线程也被称为轻权进程或轻量级进程。许多流行的多任务操作系统基本都支持线程。
  • 122. 按照系统的管理策略,线程可以分为用户级线程和系统级线程(内核级线程)两种基本类型。用户级线程指不需要内核支持,在用户程序中实现的线程都需要用户程序自己完成。系统级线程由内核完成线程的调度并提供相应的系统调用,用户程序可以通过这些接口函数对线程进行一定的控制和管理。 用户级线程不需要额外的内核开销,一般只要提供一个线程库即可,剩下的工作就主要由用户自己负责了。但是由于用户级线程与系统内核无关,当一个进程因I/O而被调度程序切换为等待状态时,属于该进程的某个执行线程可能仍然处于执行状态。 系统级线程的调度由内核完成,不需要更多用户干预,但要占用更多的系统开销,效率相对低一些。
  • 123. 线程也是系统中动态变化的实体,它描述程序的运行活动,在内存中需要记录。线程的记录信息要保证系统能够准确地进行线程切换。 在线程的生命周期里,线程作为一个基本的执行单位而存在,不断地在执行和停止的状态之间转换。线程的基本状态是执行、就绪和等待。 线程的同步是一个相当关键的问题。线程之间的通信相对容易,而线程间的同步问题需要更仔细地对待,特别是用户级线程,这个问题相当突出。
  • 124. 2.3.2线程和进程 进程是操作系统资源分配和系统调度的基本单位,每一个进程都有自己独立的地址空间和各种资源,线程也是一种系统调度的基本单位,多个线程可以共享一个进程的资源,在存储方面,线程占用的资源更少。 进程的调度主要由操作系统完成,而线程根据其类型的不同,可以由系统调度(内核级线程),也可以由用户进行调度(用户级线程)。
  • 125. 进程调度的过程中要进行切换,切换现场的保护与恢复要求对进程上下文做完整的记录,要消耗一定的存储资源和处理机时间;线程共享进程的资源,可以在进程内部切换,不涉及资源保存和内存地址变换等操作,可以节约大量的空间和时间资源。因此,对于切换频繁的工作任务,多线程方式比多进程方式可以提供更高的响应速度。 多个线程共享同一进程的资源,线程相互间通讯容易。而进程间通讯一般必须要通过系统提供的进程间通讯机制。 进程和线程都是用来描述程序的运行活动,是存在于系统存储区中的动态实体,都有自己的状态,整个生命周期都在不同的状态之间切换。
  • 126. 2.3.3 Linux系统的线程 Linux可以同时支持内核级线程(也称为系统级线程)和用户级线程。 Linux的系统级线程在表示格式、管理调度等方面与进程没有严格的区分,都是当作进程来统一对待。 Linux系统级线程和进程的区别主要在于资源管理方面,线程可以共享父进程的部分资源(执行上下文)。在Linux系统中,线程共享资源的类型是可以控制的,系统调用clone里有五种形式的clone:CLONE-VM(存储空间),CLONE-FILES(文件描述表),CLONE-FD(文件系统信息),CLONE-SIGHAND(信号控制表),CLONE-PID(进程号)。
  • 127. Linux的内核级线程和其他操作系统的内核实现不同。大多数操作系统单独定义描述线程的数据结构,采用独立的线程管理方式,提供专门的线程调度,这些都增加了内核和调度程序的复杂性。而在Linux中,将线程定义为“执行上下文”,它实际只是进程的另外一个执行上下文而已,和进程采用同样的表示、管理、调度方式。这样,Linux内核并不需要区分进程和线程,只需要一个进程/线程数组,而且调度程序也只有进程的调度程序,内核的实现相对简单得多,而且节约系统的用于管理方面的时间开销。但是,Linux系统使用相对复杂的进程控制块来记录信息,而线程本身的控制信息很少,完全可以采用相当简单的线程控制块数据结构,这就造成了内存空间的一定浪费。
  • 128. 一个值得注意的问题是,在Linux系统中,专门有一种称为kernel threads的线程,直译为内核线程,它和我们这里讨论的系统级线程(kernel level threads)在Linux系统中是两个完全不同的概念,它们的区别,将在4.3节“Linux进程调度”中详细介绍。 Linux支持POSIX标准定义的线程(pthreads),提供用户级线程支持。利用这样的线程库函数,用户可以方便地创建、调度和撤销线程,也可以实现线程间通信,而且这些线程还可以映射为系统级线程,由系统调度执行。实现用户级线程创建的函数是pthread-create。
  • 129. 2.4 小结 进程是现代操作系统的核心概念,它用来描述程序执行的过程,是实现多道操作系统的基础。和进程联系密切的概念是程序、作业和线程,正确地区分和理解这些概念,有助于正确地理解和认识计算机操作系统本身。 Linux系统中基本没有区分进程和线程,它们都使用相同的描述方法,使用相同的调度和管理策略。描述进程的静态数据是进程控制块PCB。在Linux等多道操作系统中,程序是并发执行的,进程的个数总是多于系统CPU的个数,宏观上所有进程同时都在运行,微观上这些进程轮流使用CPU,在执行、等待和就绪等基本状态之间转换,直到执行完成。
  • 130. 习题 2-1 什么是作业?简述Linux系统作业的概念。 2-2 作业、程序和进程有什么区别? 2-3 进程能不能理解为由伪处理机执行的一个程序?为什么? 2-4 什么是进程间的互斥和同步? 2-5 并发进程间的制约有哪几种?引起的原因分别是什么? 2-6 Linux系统中的线程有哪几类?分别是如何描述和管理的? 2-7 访问Internet,了解Linux系统进程控制块的现状,有哪些改进,你认为改进方案如何?
  • 131. 第3章 存 储 管 理3.1 虚拟存储器 3.2 内存管理方式 3.3 80386段页机制 3.4 Linux存储管理 3.5 小结 习题
  • 132. 每一个要运行的程序,必须首先进入内存,然而,每一台计算机的内存容量都是有限而宝贵的。存储管理的任务是方便用户使用存储资源,在有限的物理空间内使更多的用户进程高效地获得和使用尽可能多的存储空间,从而提高系统的整体性能。 现代操作系统中普遍采用基于虚拟存储器的概念来统一管理内存和外存,实现逻辑上的大容量存储空间。
  • 133. 本章首先介绍虚拟存储器的基本概念及使用虚拟存储器的依据和出发点——局部性原理,即在程序的运行过程中,总是集中地访问某一个程序段。根据这样的原理,可以把物理内存按照一定的规则划分为小部分,每次只装入某个进程必要的一部分内容就开始运行,在运行过程中,再根据需要装入新的内容。不同的划分规则形成不同的存储管理技术,我们简单介绍分区、页式、段式和段页式管理的基本思想。接着介绍Intel 80386硬件存储管理机制,最后学习Linux系统在这种硬件平台的基本存储管理机制。
  • 134. 3.1 虚拟存储器 计算机系统的存储器分为内存(主存)和外存(硬盘)。内存的价格昂贵,速度高,存储容量有限;外存价格便宜,速度慢,存储容量很大,适合于存放大量数据。为了使更多的用户进程合理、充分地使用存储资源,操作系统统一管理内存和外存,即把内存中暂时不用的内容放在硬盘上,内存中就可以腾出一部分空间,可以从硬盘装入其他迫切需要的内容。因此,从效果上看,计算机系统好像为用户提供了一个其存储容量比实际主存大得多的存储器。人们称这个存储器为虚拟存储器。
  • 135. 3.1.1 局部性原理 实验证明,在几乎所有进程的执行过程中,某一个特定的时间段中,CPU不是随机地访问整个程序或数据,而是集中地访问程序或数据的某一个部分。进程的这种访问特性称为局部性原理。 与CPU访问该局部内的数据和代码的次数相比,局部段的变化很缓慢,正是基于这样的原理,我们才有可能实现虚拟存储管理。把进程的所有内容划分为一个个小的部分,首先只把系统所必需的部分数据装入内存,其余部分就放在外存中,开始运行之后,再把所需要的其他部分换入内存,同时把不再需要的部分从内存中换到硬盘或者清除掉。当然,与之相配合,实际的内存也要划分为对应的小部分。
  • 136. 这种内外存之间的数据交换对用户进程来讲是透明的。从用户进程的角度来看,系统好像提供了一个很大的内存一样,整个进程都能装进去而且正常运行,这种逻辑上的大容量存储空间就可以称为虚拟存储器。实际上,是操作系统的存储管理起了作用,用多次内外存数据交换的时间换来了大容量的并不真正存在的(虚拟的)内存。因此,可以想象,访问虚拟存储器的速度要比访问真正内存的速度要慢。
  • 137. 3.1.2 虚拟地址和虚拟地址空间 内存中同时存在多个进程,每个进程的地址都是以0地址作为起始地址的虚拟地址空间,这个虚地址空间可以是线性的(一维的),也可以是多维的,这要取决于系统采用的存储管理方式。进程中的每一个指令和数据在这样的虚地址空间中都有一个惟一确定的地址,即虚拟地址。 每一个进程都具有各自独立的虚拟地址空间,而整个系统只有一个物理地址空间。任何一个要执行的进程,都必须进入真正的内存中,在内存的物理空间中存在,这就需要在虚拟地址空间和物理地址空间之间建立适当的映射关系。通过这种映射关系,逐部分地把存在于虚拟地址空间中的进程要执行的
  • 138. 部分放在物理地址空间中,而其他暂时不执行的部分放在外部存储器中,内外存动态地传递数据,最终完成整个进程所执行的任务。这种映射,也称为地址变换,是操作系统在硬件的配合下实现的。 系统中的每一个进程,都有一个惟一的地址映射关系,也就是说,虚拟地址空间到物理地址空间是一个多对一的映射关系。这样,不同的进程有不同的虚拟地址空间和映射变换,可以方便地实现进程之间的存储保护,避免数据和程序遭受其他进程无意或者恶意的访问,同时,它们都映射到惟一的物理空间,可以通过多个进程同时映射同一个物理地址的方式实现数据和程序的共享。
  • 139. 3.2 内存管理方式 虚拟存储的每一个要运行的程序,都必须首先进入内存,但是,每一台计算机的内存容量都是有限而宝贵的。管理技术,通常是基于局部性原理的,即把整个进程的虚拟地址空间划分为小的部分,同时把内存也划分为小的部分,在虚拟地址空间和物理地址空间之间建立特定的映射关系,进程的内容分批分期进入内存中特定的位置,其余部分在外存中,在需要的时候再传递到内存,用内存和外存的统一管理来实现内存扩充。
  • 140. 在虚拟存储技术的发展过程中,使用了不同的地址空间划分方法和映射关系,这些不同的划分和映射对应于不同的存储管理方式,本节介绍几种能够实现虚拟存储的地址空间划分方式。 3.2.1 页 把进程的虚拟地址空间划分为相等大小的部分,每个部分称为页(page),同时把物理内存空间也按照页的大小划分为小的部分,称为页面(page frame,也称为页架或页框)。对于80386体系,页和页面的大小都为4K字节。
  • 141. 在页和页面之间建立一一映射关系,连续的一维虚拟地址空间可以分别存放在不同物理空间中,因此,物理存储中,每个页面内部地址连续,而页面之间的地址可以是不连续的。页和页面之间的映射关系记录在一个表格中,这样的表称为页表。每一个进程使用惟一的页表,页表的每一项数据称为页表项,表示虚拟空间中某一页和实际物理空间中某一页面的对应关系,页表也存储在物理空间内,如图3.1所示。
  • 142. 图3.1 页式管理:页表(左)及相应的页、页面对应关系(右)示意图
  • 143. 从上图可以看出,连续的一维虚拟空间经过变换,映射到物理空间中不连续的页面中。利用分页机制实现虚拟存储管理称为页式存储管理。管理过程中,内外存的数据传递是以页为单位。页式管理采用请求调页或者预调页技术实现内外存的统一管理,内存中同时只存放少量经常执行或者即将执行的页,而其他不经常使用或暂时不会执行的页,存放在外存中,等需要的时候再调入内存。 利用分页技术将一维连续虚拟空间划分为一个个页,进程的虚拟地址由两个部分组成:页号P和页内地址(偏移量)W。这两个部分的虚拟地址经过地址变换后,映射到物理内存的对应单元。具体的地址变换过程如图3.2所示。
  • 144. 图3.2 页式内存管理地址变换示意图
  • 145. 操作系统为每一个进程维护一个独立的页表,进程正在执行的时候,页表信息记录在页表控制寄存器中,系统根据寄存器的值得到该进程对应页表的地址,同时利用页号,就可以得到该页对应的页表项。查找页表,获得了页表所映射的页面号,由页面号和页内地址,就可以直接找到内存中的对应存储单元。 在整个变换过程中,需要两次访问物理内存,第一次是查找页表,第二次是获取数据。为了提高效率,硬件一般提供一个高速的联想寄存器,构成一个快表(translation lookaside buffer),把当前进程中经常使用的页表项放在快表中,地址变换过程中,首先访问快表,如果该页表项存在于快表中,就
  • 146. 可以直接得到对应的页面号,如果不在快表中,再去查找页表得到页面号,快表的访问速度要比内存快得多,这样就可以提高内存的访问速度。 采用页式管理,实现了进程的程序和数据非连续存放,对内存和外存统一管理,得到更大的虚拟存储空间,可以同时容纳和运行更多的进程,有利于系统整体性能的提高。缺点是增加了系统开销,而且需要一定的硬件支持。由于虚拟空间是连续的,整个进程按照一维地址顺序排列,同一个程序段在分页的过程中,可能分别位于不同的页中,代码和数据的共享比较困难。
  • 147. 3.2.2 段 段式管理的基本思想是把整个程序按照逻辑结构划分为不同的段,每个段可以是一个函数(过程)或者数据,有自己的名称,段大小是不相等的,段与段之间不存在顺序关系。这样,进程具有一个二维的虚拟空间。 内存的管理以段为单位,把正在执行的段放在内存中,其他段暂时放在外存中,当需要执行时再传递到内存中。这样,也可以实现大容量的虚拟存储器。
  • 148. 段式管理中,进程的虚拟地址是二维的,由段号和段内偏移地址构成。与页式管理的区别在于,段号是不连续的,段的大小是可变的。在二维虚拟空间与物理空间之间需要建立一一映射关系,即地址 变换,这种变换关系记录在一个称为段表的表格中,系统为每一个进程维护一张段表,通过查找段表,就可以得到虚拟地址所对应的物理单元。 段式存储管理的优点在于使用了大小可变的虚拟地址空间划分方法,按照程序的固有逻辑关系来分段,便于进程之间存储共享。但是,地址变换关系更为复杂,需要更多的硬件支持,实现起来更为麻烦,同时也带来了更大的系统开销。
  • 149. 3.2.3 段页 段页式存储管理,综合利用段式和页式管理的思想,把整个二维虚拟空间先分段,然后在段内分页。以页为最小的存储管理单位来实现虚拟存储。一方面可以按照程序的逻辑关系来划分进程空间的段,另一方面使用页来存放每一个段的内容,内外存交换以统一格式和大小的页来进行。 这种管理模式下,虚拟地址要包括三个部分:段号、页号和页内偏移地址,地址变换也要经过两层次映射才能够实现,首先从二维虚拟空间映射到一个线性虚拟空间,然后再从线性空间映射到物理空间。可以想象,整个变换过程更为复杂,需要大量的硬件支持和系统开销。
  • 150. 3.3 80386段页机制 上一节,我们介绍了不同的存储管理方法:页式、段式和段页式。这些方法的依据都是局部性原理,区别在于存储空间的划分和映射方法。这些管理方法都需要一定的硬件支持。本节,针对Linux系统的主要平台之一Intel 80386(简称I386)系统,介绍该系统的段页式硬件支持机制。
  • 151. 3.3.1 实模式与保护模式 80386是Intel公司推出的32位CISC芯片,此后,该公司又相继推出80486、Pentium(P5)、Pentium Pro、PⅡ、PⅢ等一系列向下兼容的32位芯片。本节讨论的特点是针对以I386为代表的整个芯片系列。 I386有两种工作模式,实地址模式和虚拟地址模式,后者又称保护模式。实地址模式与早期的8086兼容,不能启用分页机制,不区分特权级,分段机制也受到限制,直接寻址方式,只能寻址1MB。
  • 152. I386的保护模式支持分段机制,整个虚拟空间可以划分为16K个段,每个段的大小可变,最大能够达到4GB,每个段可以提供独立的段内保护,支持二级分页机制,每个页面4KB,提供段页式存储管理的硬件支持。同时,在同一个任务内部,还提供4种(0~3)保护特权级,某一级特权i只可以访问所有其他大于等于这一特权级(≥i)的程序段。
  • 153. 3.3.2 地址空间 在I386体系结构中,提供段页式存储管理的硬件支持,和内存管理有关的地址空间包括逻辑地址空间、线性地址空间和物理地址空间,在存储过程中,要经过相对独立的两级地址变换。第一级使用分段机制,把包含段地址和段内偏移地址的二维虚拟地址空间转换为一个线性地址空间(也是虚拟地址空间),第二级使用分页机制,把线性地址空间转换为物理地址空间。这种转换关系可以用图3.3来描述。
  • 154. 图3.3 地址映射关系示意图
  • 155. 虚拟地址空间到线性地址空间的转换关系由段描述符表(简称段表)来描述,段表的每一个数据项记录一个段到线性地址的关系,段表存放在线性地址空间中。线性地址空间到物理空间的转换关系由页表描述,页表存放在物理地址空间中。 每个虚拟地址空间(16K个段)可以分为相等的两个部分,一半称为全局虚拟地址空间,由全局段描述符表(Global Descriptor Label, GDT)映射,另一半称为局部虚拟地址空间,由局部段描述符表(Local Descriptor Label, LDT)映射。
  • 156. 系统中所有进程共享一个全局段表(GDT),而每一个进程都有自己的局部段表(LDT)。当进程发生切换时,GDT不变,而LDT更新为正在执行进程的LDT,因此,所有进程共享GDT所映射的物理地址空间,每一个进程都有自己单独的地址空间(由LDT描述)。 线性地址空间划分为大小相等的页,每页为4KB,与之对应的物理地址空间划分为大小相等的页面,页面的大小也是4KB。I386体系结构采用二级分页机制,线性地址到物理地址的映射使用一个二级页表,二级表中的第一级称为页目录,每个页目录项指向一个二级表,这个二级表就是一个页表,每一个表项记录该表对应的表架的基地址,这个基地址和偏移量一起就构成整个物理地址。
  • 157. 3.4 Linux存储管理 Linux系统本身采用段页式存储管理,使用最小限度的段机制和三级分页机制。在I386保护模式下,系统可以获得大容量的虚拟存储,并且在各进程之间实现有效的存储共享和保护。 3.4.1 段页设置 Linux系统最低限度地使用I386体系的分段机制,把整个虚拟地址空间直接映射为线性地址空间,一个虚拟空间只包含一个段,段的大小为4GB。也就是说,一个进程最大可以占有4GB的空间。
  • 158. Linux 2.2.16及以前的版本,在全局段表(GDT)中,每一个进程(每一个虚拟地址空间)有两个静态的表项,其中一项是进程的任务状态段(Task Status Segment,TSS),这项记录着进程切换过程中的CPU现场状态,另外一项是局部段表(LDT),LDT项是这个进程对应的局部段表的入口。而每个进程的局部段表中只有三个表项,一个空表项、一个用户数据段和一个用户代码段,用户数据和代码都从地址0开始,大小为3GB,称为用户空间。所有进程的3GB~4GB线性空间,都由系统共享,存放系统数据段和系统代码段,称为内核空间。
  • 159. Linux系统使用I386提供的四级保护机制中的两级,0级由系统内核使用,而3级由用户程序使用。Linux内核存储在内核空间。用户进程有各自的虚拟地址空间,都使用从0~3GB的线性空间,而内核空间映射到每一个用户线性空间的3GB~4GB的地方,由所有进程共享。 根据硬件提供的保护机制,处于内核空间的内核代码可以访问正在执行进程的用户空间。用户空间的代码只能访问本空间的内容,不能直接访问内核空间的内容,用户进程只能通过中断或者系统调用访问内核空间,这时,触发硬件的特权级转换(由3级转换为0级),操作系统转入内核空间中执行,
  • 160. 执行完毕后,依靠硬件设置实现再次切换,重新进入用户空间。用户空间之间除了特定的共享空间之外,不可以相互访问,这就比较方便地实现了存储共享和保护。 整个线性空间通过分页的方式映射到物理空间。每页大小为4KB,因此整个4GB的线性空间可以分为1K(1024)个页(page),Linux系统采用三级分页机制,对页建立三级索引,分别称为页目录(page directory)页中间目录(page middle directory)和页表(page table)。由于I386体系结构的限制,在I386平台上的Linux系统采用两级页索引,页目录和页中间目录合二为一。
  • 161. 3.4.2 地址映射 Linux系统的虚拟空间分为连续的段,分别为用户空间和内核空间,直接映射到线性空间中。在地址变换过程中,主要考虑线性空间到物理空间的映射关系。 在I386平台上的Linux系统采用两级页索引,为页目录和页表。线性空间的页和物理空间的基本单位页面(page frame)之间存在对应关系,这种关系用页表(page table)来描述,每个页在页表中占一项,每一项为4字节,要描述整个线性空间,页表要4MB。把所有页表也划分为4KB为单位的页,共有1K个这样的页,这些页的地址采用页目录(page directory)来记录,页目录的每一项描述
  • 162. 存放页表的一个页与实际页面的对应关系,每一项也占用4字节。这样,描述整个线性地址空间需要的页目录占用一页。 线性地址由三个部分组成,分别为页目录索引、页表索引和页内偏移地址。第一部分页目录索引描述要访问地址在页目录表中的位置,通过这个索引,就可以得到一个记录页表的内存单元;第二部分页表索引描述待访问地址在页表中的位置,通过查找页表,就得到待访问地址所在的页面;第三个部分页内偏移地址,描述待访问地址相对于页面基地址的偏移量。根据这三部分资料,就可以访问到内存中相应的内容。整个线性地址包括32位,其中页
  • 163. 目录索引和页表索引各占10位,寻址范围为1K,正好是页表和页目录表的大小,而页内偏移地址占12位,寻址范围为4K,等于页的大小。这种地址变换可以参看图3.4。
  • 164. 图3.4 Linux在I386平台的地址变换
  • 165. 从上面的描述可以看到,要访问内存中的某一内容,通过地址变换,首先查找页目录表,接着查找页表,最后才能访问到真正存放的数据,整个过程要三次访问物理内存,因此,记录一个进程中经常访问页的地址的快表(translation lookaside buffer)是必不可少的。地址变换过程中,首先访问快表,如果该页表项存在于快表中,就可以直接得到对应的页面号,如果不在快表中,再去查找页目录表和页表。
  • 166. 3.4.3 共享与保护 Linux系统的每一个进程拥有4GB的虚拟空间,这个空间也就是线性空间,在I386系统下,对应为1K个大小为4KB的页。其中0~767个页对应的3GB空间为用户空间。而3GB~4GB的区域映射为系统空间。 实际上,整个物理内存被映射到从3G(0xc0000000)开始的一段线性空间中,在启动过程中,这个区域的页目录和页表首先建立,也就是说,整个物理内存从启动开始就处于内核态,由系统所控制。所有物理内存可以由内核页目录和内核页表来寻址,这种关系是固定不变的,而且对于每一个虚拟空间都相同,这一方面保证了系统对物理
  • 167. 内存的快速访问和有效控制,另一方面也保证了所有进程可以共享系统空间。 进程对系统空间的共享是在严格的限制下进行的,这种限制利用了I386提供的特权级保护机制。进程的虚拟空间包括了系统(内核)空间和用户空间两个部分,它们分别处于不同的特权级。内核空间特权级为0,进程执行这个空间的指令,称为处于内核态(或者系统态);用户空间的特权级为3,进程执行这个空间的指令,称为处于用户态。用户态和核心态是同一进程的两种不同运行模式,进程在用户态和核心态执行时分别访问位于用户空间和核心空间的堆栈和数据结构。处于内核态的进程可以访问同一进程的用户空间,反之则不可以访问。
  • 168. 一个进程可以在这两种不同的特权级之间切换,用户态通过中断或函数调用就可以转入系统态,执行内核空间的指令。而从系统态切换到用户态,则需要一定的硬件支持。 在进程建立之后,首先建立页目录,然后系统根据实际需要,动态地分配一部分物理内存,建立用户页表、页表项以及相应的页目录项,进程在用户空间中将根据这些值来寻址,访问物理内存。在获得一部分内存之后,用户进程即可以开始执行,执行的过程中,当进程访问到还没有映射在内存中的页时,进程发出页面请求,操作系统才根据需要把放在外存中的页的内容传送到内存,同时建立内存页面与进程页的映射关系。
  • 169. 每个进程虚拟空间中的0~3GB分别采用不同的映射关系,映射到不同的物理空间,虚拟空间之间是不可以互相访问的,这就起到对进程内的数据和程序保护的作用。 进程之间的共享是必不可少的,如果我们同时开两个vi的编辑窗口,它们都运行同样的程序代码,分别属于两个不同的进程,对应于不同的编辑文本(操作数据),如果分别给两个进程开两块存储空间,存放同样的程序代码,显然是对有限内存资源的极大浪费,不同的进程共享使用相同的内存代码是最好的解决办法。 Linux进程间的共享是通过把不同虚拟空间中不同的页映射到物理空间中同一页面来实现的,参看图3.5。
  • 170. 图3.5 Linux页面共享结构示意图
  • 171. 在图3.5中,两个进程分别拥有自己的页目录和页表,而页表中,对应于不同进程的页号指向内存中同样的页面,这样,同一个物理页面映射为不同虚拟空间中不同的页,两个进程都可以根据自己的地址映射关系访问同一块内存,实现了内存的共享。这样的共享方式实现简单,易于理解,也不占额外的物理内存,但是,一旦共享页面的状态或者内容发生变化,所有共享该页面的进程的页表都要修改,这就需要多次访问内存,影响系统的效率。 Linux系统还采用保护技术,实现进程用户空间内部不同存储段之间的保护。
  • 172. 在系统运行期间,进程之间存储共享可以节约大量的存储空间,同时可以提高系统的整体效率,但是,共享必须在保证安全的前提下进行,这就需要必要的保护措施。虚拟空间划分为系统空间和用户空间,按照一定的映射规则与物理空间建立联系,系统多个进程之间共享整个系统空间,多个用户进程也可以共享一段物理内存。在Linux系统中,用户空间和系统空间的共享、不同进程用户空间之间的共享以及进程用户空间的虚拟存储段,都可以得到有效的保护。
  • 173. 3.4.4 分配与回收 系统开始运行时,整个物理内存都映射到内核空间,由内核根据需要进行物理内存页面的分配或释放。用户进程建立时,分配相应的内存页面并建立用户进程虚拟空间与所分配页面的映射关系,在进程执行过程中,还要针对实际情况,动态地分配和回收页面,进程进入僵死状态后,除了进程控制块(PCB)所占据的页面之外的所有内存都释放,最后PCB释放,进程终止。因此,物理页面的分配和释放机制及其相关数据结构是操作系统虚拟存储管理的关键部分。
  • 174. 在执行过程中,每一个进程要记录自己使用的所有页面以及它们的映射关系(页表和页目录),这些信息以指针的形式记录在进程的PCB中。同时,系统对所有内存的使用情况也要做精确的记录,这是内存进一步分配和回收的依据。 1. 空闲页面表示 Linux主要采用Buddy(伙伴)算法有效分配和释放物理页面。系统的页面分配和回收都是以2的k次幂(0≤k≤NR-MEM-LISTS-1,整数)个页面为单位,称为页块,也就是说以1页、2页,直到2NR-MEM-LISTS-1页大小的页块为单位连续分配。具体来讲,对于I386系统,在2.2.16版本中,NR-
  • 175. MEM-LISTS默认值等于10,在文件mm/page-alloc.c中定义,每个页面大小固定(为4KB),所以,内存分配的最小单位是4KB,最大为2MB(29×4KB)。 Linux的空闲物理页面分配采用链表和位图结合的记录方法。系统定义了一个称为free-area 的数组,数组的大小为NR-MEM-LISTS。 free-area数组的每一个元素都包含一个空闲页块双向链表的头指针和一个位图map,描述某一种页块的空闲情况。每一个数组元素对应的链表,记录2k大小页块的信息,k为数组元素的下标。具体来讲,第一个元素(下标为0)描述单个空闲页的信息,第二个元素(下标为1)则描述以2个页为一个块的
  • 176. 空闲页块,第三个元素(下标为2)描述以4个页为一个块的页块信息。free-area数组的元素记录双向链表的头指针,而双向链表的每个节点包含空闲页块的起始物理页帧编号。free-area数组的元素中包含的位图map记录这种页块的具体分配使用情况,位图中的某一位置1,则表示对应的页块被使用。这样,所有单个空闲页面组成的双向链表挂在free-area数组的0号元素之后,所有2k页面大小的空闲块组成的双向链表挂在free-area数组的k号元素之后,同时,每一个空闲块的使用情况可以通过对应的位图描述。这种关系示意性地描述在图3.6的左半部分。
  • 177. 图3.6 Linux系统空闲内存示意图
  • 178. 在图3.6中,如果物理内存中某一部分的空闲情况如图右半部分所示,free-area数组的0号元素描述大小为1页的空闲页块,那么第8号页面就是free-area数组的0号元素所对应的双向链表的头接点。同理,第5号和第0号页面分别是free-area数组的1号元素和2号元素所对应的双向链表的头接点。free-area数组的k号元素所对应的第N位为1,则表明该元素对应的链表中第N个页块是空闲的,这个页块的大小就是2k个页面。从图中也可以看到,free-area数组的各元素所记录的页块大小各不相同,从小到大依次是两倍的关系,同时对应用来记录页块分配情况的位图大小也各不相同,free-area数组元素号越大,页块越大,页块的数目就越小,而相应的位图也越小。
  • 179. 2. 页面分配与回收 Linux采用Buddy算法来分配和回收物理页面,每次处理都是以2k(0≤k≤NR-MEM-LISTS-1,整数)个页面为单位。分配页面采用最先适应算法,当要分配一块内存时,首先确定需要内存的大小,如果需要的内存在2k到2k+1(0≤k≤NR-MEM-LISTS-1,整数)个页面大小之间时,系统要为它分配的页面就是2k+1个,系统在free-area数组中搜索从第k+1个元素对应的双向链表中开始搜索,找不到时再搜索第k+2个元素对应的双向链表,直到找到大于或等于要求尺寸的最小块的信息。如果找到的空闲块正好是2k+1个页面时,直接从free-area删除该块,返回首地址,如果找到的空闲块大于所
  • 180. 需要的页面,则把空闲块一分为二,前半部分插入free-area数组前一个元素所指的链表中,取后半部分,如果后半部分还大,继续对半划分,直到分得的后半部分等于需要的页面为止。页面分配之后,对应的各位图的位也要相应设置。Linux采用的这种分配算法称为最先适应算法。 随着页块的不断分配,系统的内存逐步被划分为一个个小的块,这些块有些正在使用,而另外一部分则是空闲块,但是连续可用的块却越来越少,这种情况称为内存的碎片化。因此,物理页块使用完之后要及时回收,而在回收空闲块的同时,还应当将小的空闲页块重新组合成大的页块。Linux系统回收空闲块时,根据位图表对应的值判断回收块相邻
  • 181. 位置的页块是否空闲,如果和回收的页块大小相等的相邻页块刚好是空闲的,则可以把这两个页块组合成一个大的页块,这一过程一直继续,直到这个大页块的相邻块不等于这个块或者正在使用为止,这时还要修改对应的位图值,并把这个大的页块插入到free-area数组对应元素所指的链表中。 Linux采用的Buddy算法可以实现内存的快速分配和回收,同时也能够有效地处理内存碎片化问题,总体效率比较高。但是,它对内存的快速分配是建立在内存需求量是2的整数幂个页面的基础上的,如果很不巧,我们需要的内存量是33KB,根据Buddy算法,在I386系统中,实际分配的是16个连续的页面(64KB),大约50%的内存就浪费掉了。
  • 182. 在整个分配过程中,这样隐性的内存浪费量是相当惊人的。因此,可以说,这种算法内存分配和回收的高效率是通过牺牲系统内存资源的利用率换来的。
  • 183. 3.5小结 Linux操作系统可以统一管理内存和外存,实现逻辑上的大容量虚拟存储空间。利用这样的技术,系统有限的物理存储区域中可以存放更多的进程,这些进程轮流使用处理机,实现系统整体效率的大幅度提高。 进程的执行过程中,某一个特定的时间段中,CPU总是集中地访问程序或数据的某一个部分,这种规律称为局部性原理,这个原理是虚拟存储实现的依据。根据这一原理,把进程的虚拟空间划分为一个个小的部分,首先只把系统所必需的部分数据装入内存,其余部分就放在外存中,开始运行之后,再根据进程执行情况把所需要的其他部分换入内存,
  • 184. 同时把不再需要的部分从内存中换到硬盘或者清除掉。与这样的方式相配合,物理内存也划分为对应的小部分。 不同的虚拟空间和物理空间划分方法得到不同的存储管理方法,常用的能够实现虚拟存储的划分方法有页式、段式和段页式。页式管理把虚拟空间和物理空间划分为大小相等的部分,分别称为页和页面,以页和页面为单位进行存储管理;段式管理把虚拟空间按照程序固有的逻辑关系划分为大小不等的段,每一个段对应程序的一个逻辑单位,以段为单位进行存储管理;段页式管理对虚拟空间先分段,再分页,最小单位是页,同时具有段式和页式管理的优点,但是整个管理的系统开销增大,而且还需要有硬件的支持。
  • 185. 以I386为代表的向下兼容的一系列芯片在保护模式下,提供段页式存储管理的硬件支持。一个虚拟空间可以划分为16个段,最大的段可以达到4GB,同时支持分页功能,页面大小为4K,提供两级页表。同时提供0~3四个特权级,对不同特权级运行的进程实现保护。 Linux最低限度地使用I386系统的分段机制,使用0(系统级)和3(用户级)两个特权级。每个虚拟空间是线性的,大小为4GB,分成用户空间0~3GB和系统空间3GB~4GB两个部分。所有系统空间都映射到同一段物理内存,实现系统段共享,操作系统位于系统空间,以0级特权运行,用户进程位于用户空间,以3级特权运行,使用页目录、页表这两级分页机制。
  • 186. 利用I386提供的硬件机制,Linux系统可以方便地实现系统空间和用户空间之间、不同进程用户空间之间以及同一进程用户空间不同虚拟存储段之间的共享和保护。 Linux系统的空闲物理内存的管理采取Buddy算法,管理内存的最小单位是2的整数次幂个页面大小,利用位图和链表相结合的办法记录空闲内存信息,内存分配采用最先适应算法,可以快速分配和回收空闲内存页面,同时也能够有效处理内存碎片化问题。 以此为基础,下一章我们进一步学习虚拟存储管理中内存外存之间数据传递——交换调度的基本算法与过程。
  • 187. 习题 3-1 计算机系统中,虚拟地址空间和物理地址空间分 别对应着什么? 3-2 分页和分段式内存管理有什么区别? 3-3 为什么提出段页式管理?它与页式、段式管理有何区别? 3-4 段页式管理的主要缺点是什么?有什么改进办法? 3-5 Linux系统中如何利用I386的段页机制? 3-6 Linux中,系统空间和用户空间之间、不同进程用户空间之间以及同一进程用户空间不同虚拟存储段之间如何实现共享和保护?各需要什么硬件支持?
  • 188. 3-7 Linux系统的内存分配与回收采用什么算法?有什么优点?有什么缺点?提出你的改进思路。 3-8 考虑如下的程序段: #include #include int main(void) { printf("AAA"); sleep(6); return 1; }
  • 189. 在Linux系统中,运行这个程序所建立的进程的虚拟空间为多大?其中系统空间、用户空间各多大?进程实际占用的物理内存是多少?分别用来存储什么内容?运行这个程序,利用系统命令查看实际使用的内存量。
  • 190. 第4章 调 度4.1 调度的层次 4.2 Linux交换调度 4.3 Linux进程调度 4.4 小结 习题
  • 191. 设计操作系统的主要目标是充分利用硬件资源使其发挥最大的效能。处理机(CPU)资源,又是其中最重要的一项,让它尽可能处于工作状态,是操作系统管理功能的关键。调度针对的主要是处理机资源的分配问题,因而处理机管理的核心是调度。 处理机调度的主要指标有:周转时间、吞吐量、响应时间和设备利用率等。根据不同的使用场合、不同的系统需求,选取合适的调度算法,采用不同的管理侧重点,使系统达到预期的性能指标是调度管理的主要任务。 本章首先介绍处理机调度的层次和目标,然后,以单处理机微机系统为背景,具体讨论Linux系统交换调度和进程调度的基本原理和实现方法。
  • 192. 4.1 调度的层次 处理机调度也是分层次的,按照调度发生频率依次是:作业调度、交换调度、进程调度和线程调度。 作业调度,是针对用户提交的作业,在已经输入的作业中,按照某种策略,选取合适的作业投入运行。 交换调度,又称中级调度。针对系统中已经开始运行的进程,把内存中暂时不会执行的内容交换到外部存储器的特定区域中,而把外存中处于就绪状态的进程交换到内存中,准备投入执行。 进程调度,控制进程在执行、就绪、等待等各种状态之间转换经历的过程。特别是从就绪到执行的转换,系统从处于就绪状态的所有进程中选择合适的一个,分配处理机资源,投入执行。
  • 193. 线程调度,系统内核针对线程的调度情况,选中就绪线程并占有处理机,转入执行状态。 参看图4.1。 图4.1 Linux系统调度层次示意图
  • 194. Linux系统高级调度非常简洁,或者也可以说没有作业调度的概念,作业一旦输入,就直接进入内存,建立相应的进程,进入下一级的调度。交换调度主要涉及系统存储管理的内容,一方面根据正在执行进程的要求,把所需要的页换入内存,同时按照一定的规则保证系统总是有足够的空闲内存页面,一旦发现系统空闲页面低于某一个临界值,就把内存中的页面按照一定的算法清除掉一部分,直接丢弃或者是交换到外部存储器中。Linux系统中的内核级线程和进程在表示、管理调度方面没有差别,系统也没有专门的线程调度,采用进程调度统一处理进程和内核级线程。因此,本章主要讨论Linux系统中的交换调度和进程调度的内容。
  • 195. 4.2 Linux交换调度 Linux系统的内存主要采用称为请求页式管理的动态管理方法。当某一个程序开始运行时,一个新的进程创建,整个可执行文件映像和该程序引用的所有相关共享库同时装入进程的虚拟地址空间中。Linux在建立进程的时候,整个执行文件映像并没有装入物理内存,只是链接到进程的虚拟地址空间中,进程只分配到极少的内存页面,占用很少的物理空间。在整个进程生命周期中,进程所拥有的内存页面总是动态变化的。管理好内存页面和外部存储器,正确地模拟内存特殊区域的工作,保证系统有足够的内存,让尽可能多的进程并发执行,是Linux交换调度的主要任务。
  • 196. 请求页式管理被认为是按照进程执行的需要而分配和使用内存的,因此也称为按需调页。为了解决进程执行所需要的页面,围绕着进程的虚拟内存结构,系统首先确定哪些虚页需要执行但它还不在内存中,然后分配必需的内存页面并把所需的页换入内存。 确定虚页是通过查找页目录和页表中相关的属性标志来实现的。虚页换入内存时,首先需要解决缺页的调入方式,其次要保证有足够的空闲内存页面,这就需要使用适当的策略来淘汰占据内存的页,这种策略称为置换算法。Linux系统采用记龄(aging)置换算法,Linux系统根据访问次数来决定是否适合换出,优先换出那些很长时间没有被访问的页面。
  • 197. 4.2.1 交换空间 现代操作系统中普遍采用基于虚拟存储器的概念来统一管理内存和外存,实现逻辑上的大容量存储空间。 从内存中换出的页面保存在外存的交换空间中,Linux系统提供两种不同类型的外存保存方式。一种是利用整个块设备,比如磁盘的一个分区,这样的分区具有特殊的格式,通常称为交换区或交换设备。另一种是利用文件系统中特殊的文件,这种文件具有固定的长度,称为交换文件。
  • 198. Linux系统可以同时管理多个交换空间,最大个数由参数MAX-SWAPFILES指定(默认值是8),在文件include/linux/swap.h中定义。交换空间按照优先级排序,当需要分配一个交换页面时,Linux首先使用仍然拥有空间、拥有最高优先级的交换空间,交换区和交换文件都可以用来存储内存中换出的页,达到扩充内存的目的。使用交换区的交换存取过程中,系统直接针对磁盘进行。交换文件是文件系统中的特殊文件,在文件系统建立之后创建。在实际使用过程中,通常以交换区为主,以交换文件为辅。首先设置能够满足日常工作需要的交换区,当需要更多交换空间的时候,临时增加几个交换文件,这样,不再需要时可以方便地撤消交换文件。
  • 199. 4.2.2 进程的内存组织 Linux系统中进程虚拟存储空间管理的基本单位是虚拟存储段(Vitual Memory Area, VMA),用vm-area-struct 结构来描述。一个VMA段是某个进程的一段连续的虚拟空间,这段存储空间的所有单元(页)拥有相同的特征,这些特征可以包括访问权限、保护情况可加锁情况等等,同时,还定义了一组建立在这个数据结构基础上的对内存的操作方法,这些操作方法具体实现进程对虚拟存储段的操作,见图4.2。进程的虚拟内存实际是由一组指向vm-area-struct 结构的指针的链表来具体实现的,链表的头接点记录在该进程所指向的mm-struct结构中。
  • 200. 图4.2 vm-area-struct 数据结构示意图
  • 201. 当可执行程序映射到进程的虚拟地址空间时,系统建立一系列 vm-area-struct结构来描述虚拟内存区域的起始点和终止点,每一个结构代表可执行程序的一个部分,可能是可执行代码,也可能是初始化的变量或未初始化的数据。随着整个vm-area-struct结构组成的链表的生成,这个结构所描述的虚拟内存区域上的标准操作函数也由Linux初始化。 进程映射到虚拟空间中并开始执行后,因为只有很少一部分被装入了物理内存,因此不久进程就会存取尚未装入物理内存的虚拟内存页,这时,处理器向Linux报告一个页故障及其对应的故障原因,根据实际情况,系统必须把进程执行所需要的内容装入到物理内存,换入工作开始了。
  • 202. 4.2.3 换入 进程内存页的换入是从缺页故障开始的,这种页故障出现的原因可能有两种,第一种情况是程序出现内存访问错误;另一种情况就是正常的缺页中断,虚拟地址有效,但其所对应的页当前不在物理内存中,这时,操作系统必须从磁盘映像或交换空间中将所需的页装入物理内存。 进程运行过程中遇到缺页中断后,系统保存当前进程的现场,当前进程进入等待状态。Linux系统转入缺页中断处理程序,根据处理器提供的缺页地址信息(在I386系统中是控制寄存器CR2),系统必须迅速地找到用来表示出现缺页的虚拟存储区所对应的vm-area-struct结构。
  • 203. 为了实现快速查找出现页故障虚拟内存相应的vm-area-struct结构的位置目标,Linux内核把所有vm-area-struct结构组成一个AVL树。如果搜索不到缺页所对应的内存区域,则说明进程访问了非法存储区,该虚拟地址是无效的,系统向进程发送SIGSEGV信号。 接着,系统进行缺页访问模式合法性检测。因为进程也有可能在虚拟地址上进行的操作非法而产生页故障。这时操作系统会同样发送内存错误信号SIGSEGV给该进程。有关页的访问控制信息包含在页表项中。
  • 204. 这两项检测通过之后,就表明该虚拟地址有效。对有效的虚拟地址,必须区分页所在的位置。如果页表项是无效但非空,则说明该页处于交换空间中,操作系统要从交换空间装入页,否则,页面就位于磁盘的可执行映像中。默认情况下,Linux会分配一个新的物理页面并建立一个有效的页表项,更新页表项的相关属性信息,把所需要的页面装入内存。 这时,所需的页装入了物理内存,页表项也同时被更新,然后进程就可以继续执行了。这就是请求页式管理的请求调页过程。 处理缺页故障过程中操作系统唤醒另外的进程占有处理机资源,当前进程转入等待状态。换入结束后,进程转入就绪状态,参与处理机资源的竞争。
  • 205. 4.2.4 换出 系统为了保证有足够的空闲物理内存,必须及时把内存中暂时不会用到的物理页面淘汰掉,或者说置换出去,可能是置换到交换空间,也可能直接扔掉,这取决于页面本身的访问情况。 Linux系统提供内核交换进程kswapd来实现页面淘汰功能。kswapd进程号为5,属于一种特殊的进程,Linux中称为内核线程,内核线程不是通常意义的线程,它是具有高优先级的实时进程,不共享其他进程的内容,本身没有虚拟存储空间,运行于内核态,直接访问物理空间,这种特性决定了它可以快速地使用内存,提高整个内存管理的效率。属于这个类型的进程还有init和bdflush等等。
  • 206. 内核线程kswapd主要是保证系统中总是有足够的空闲页面,保持整个存储管理子系统高效地运行。这个线程周期性地运行,可以保证系统总能及时释放足够多的内存页面。 交换内核线程kswapd周期性地被唤醒,首先检测现有的空闲内存页面数据,Linux系统使用固定的值作为空闲页面的警戒值。 交换内核线程kswapd是高优先级实时进程,依次通过三种途径缩减已使用的内存页面——一是缩减page cache和buffer cache;二是换出SYSTEM Ⅴ 共享内存占用的页面;三是换出或者丢弃其他进程占用的页面。释放一部分页面之后,系统再次拥有足够多的空闲页面,交换内核线程转入等待状态。
  • 207. 缩减page cache和buffer cache是Linux操作系统首选的释放页面途径。page cache是系统为了提高磁盘文件访问速度而设置的,磁盘文件中正在访问的一部分以页为单位映射到内存中。buffer cache是系统块设备使用的缓冲区,其目标是提高块设备的访问速度。在释放物理内存时,淘汰cache页面是最简便的办法。 如果缩减page cache和buffer cache没有得到足够多的空闲页面,就采取第二步措施,换出SYSTEM Ⅴ共享内存。共享页面由多个进程访问,只能换出到交换空间中,而且共享页面同时涉及到多个进程,因此在换出过程中必须依次对每一个进程的页表进行修改,这也需要多次访问内存,增加了工作量。
  • 208. 上述两种措施仍然没有得到足够的空闲页面时,系统就要对所有进程进行扫描,寻找适合换出的候选进程。好的候选进程应该有一个或多个可以丢弃或换出的页面,系统选择其中部分页面丢弃或换出。 Linux系统采用记龄(aging)置换算法。Linux系统根据访问次数来决定是否适合换出,优先换出那些很长时间没有访问的页面。与前两种途径相比,换出或者丢弃其他进程占用的页面的效率最低。 总的来看,请求页式存储管理方法在进程建立时只分配少量内存,通过页面的交换来保证进程运行的时候能够得到需要的页面,可以同时在内存中安排多个进程。但是,内存利用率的提高是以牺牲系统时间开销为代价换来的。
  • 209. 4.3 Linux进程调度 Linux系统中同时在内存中安排多个进程,这些进程相互之间竞争处理机的使用权。系统的低级调度,即进程级调度就是要按照一定的策略,从所有处于就绪状态的进程中选择最应该执行的进程,把CPU分配给它,开始执行。Linux系统的内核级线程也按照进程来对待,使用进程调度统一处理进程和内核级线程。
  • 210. 4.3.1 初始化过程及进程树 我们以Intel 386系列计算机为例,介绍Linux系统的启动过程, 现假定系统已经完成了正常安装。打开计算机电源,计算机首先从固化在主板ROM中的BIOS开始启动,BOIS对计算机的硬件进行一系列的检测,然后从指定设备的指定位置,把boot loader读入系统内存并把控制权转交给boot loader,接着,在boot loader的控制下,系统启动代码被读入内存并进行初始化工作,控制权转交给系统初始化代码后,引导整个操作系统进入内存并控制整个系统,设置各种表格和数据结构,初始化可运行队列的时候建立系统的0号进程,然后创建系统最初的进程——init进程,该进程的进程号为1。
  • 211. init进程启动内核交换线程等系统内核线程,然后根据系统提供的参数,启动相应的终端管理进程,在每一个终端屏幕上显示login字样,等待用户的登录,整个启动过程到此结束,参看图4.3。用户登录过程中,init进程启动login进程对用户的账号和密码进行验证,通过之后,由login进程启动shell命令解释进程,为用户提供操作系统的接口,接受用户的输入,解释执行用户命令,执行过程中又会创建新的进程。
  • 212. 图4.3 Linux系统启动过程
  • 213. Linux系统的所有进程共同构成一个完整的进程树,如图4.3所示。从init进程开始, init进程是所有其他进程的祖先。init产生终端管理进程mingetty,mingetty产生login,login产生用户的shell进程,然后shell产生其他用户进程,因此,其他所有进程都是由init或者它的子孙创建而来。同样,在进程结束之后,父进程也要负责该进程的最后回收工作,如果某一个进程创建了子进程之后,由于某种原因先于子进程终止,由它创建的子进程成为孤儿进程,孤儿进程的祖父进程就要负责回收工作,依此类推。最后,在系统要关机之前,init进程还要负责结束所有的进程,卸载所有文件系统并终止处理器的指令执行。
  • 214. 4.3.2 进程的组织 为了管理进程,Linux系统采用多种方式来组织处于各种状态的进程。 系统中每创建一个新的进程,就给它分配一个进程控制块(PCB), PCB是系统感知、控制进程的静态实体。系统访问PCB的频率非常高,因此所有进程的PCB都直接存放在物理内存中。Linux系统中使用一个称为task的数组来保存所有PCB的指针,Linux通过task数组来管理系统中所有的进程。每一个进程都有一个惟一标识自己的进程号PID,进程号和进程在task数组中的位置(数组元素的下标)之间是不同的。
  • 215. 同时,系统中所有的进程还构成一个双向循环队列,整个队列通过进程控制块中的两个指针next-task和prev-task来维护。某个进程在整个进程树中的位置,也通过PCB中指针描述。 为了方便进程的调度,系统把所有可运行的进程组织成一个可运行队列,系统通过当前(current)指针来区别就绪状态和执行状态,每一个CPU都有一个当前指针,指向正在使用该CPU的进程。可运行队列也是一个双向循环队列,队列中指向前后接点的指针同样存放在PCB中,它们是next-run和prev-run。系统的调度函数根据一定的规则,查找整个可运行队列,在其中寻找最值得执行的进程,给它(或它们)分配CPU,投入执行。
  • 216. Linux系统内部把所有进程分为三类,空闲线程、内核线程和用户进程。空闲线程是系统中一个特殊的具有标志作用的进程,它是task数组的0号元素task\[0\],它的进程号也是0,在源代码中记作init-task,只有当整个系统中没有进程可以运行时,空闲线程才会执行,它始终位于系统可运行队列中,也是该队列的头结点,同时它也是所有进程组成的队列的头结点。内核线程也是比较特殊的进程,它处于核心态,没有虚拟地址空间,拥有很高的优先权,一般用来完成系统管理任务,内核交换进程kswapd就是其中之一。用户进程包括所有其他进程和线程,可以在用户态和核心态两种模式下运行。
  • 217. 注意,空闲进程init-task和系统中的1号进程init在表达上很相象,但二者完全不同,空闲进程是进程组织、调度过程中的关键性标志,它本身不完成任何任务,它不会退出也不会进入等待状态,而init进程是系统启动后第一个有用的进程,它负责启动系统中相关进程,在系统要关机之前,init进程还要负责结束所有的进程,它是系统中整个进程树的祖先。
  • 218. 4.3.3 进程调度时机 调度函数是Linux系统中执行最为频繁的一个,它的主要目标就是选择合适的进程占有CPU,实现程序的多道执行,充分提高CPU的利用率。调度函数通过对每个进程PCB中相关信息查询,按照一定的算法,在可运行队列选择进程。如果选中的进程并不是当前占有处理机的进程,调度函数还负责保存当前进程的执行现场(进程上下文),然后恢复选中进程的进程上下文使之顺利执行。 Linux系统中没有设置专门的调度进程,在需要调度的时候,调用一个特定的调度函数来完成调度功能。一般来讲,Linux系统中的进程调度发生的时机有下面几种。
  • 219. (1) 用户利用系统提供的函数调用创建一个新的进程时,系统把它加到可运行队列中,返回该进程的进程号。这时,调度函数开始执行,这样的方案可以保证系统具有很好的响应特性。 (2) 当正在执行的进程申请某种暂时无法获得的资源或者为了与其他进程保持同步,需要等待某个事件的发生,进程的PCB进入相应的等待事件队列中,进程转入等待状态; 当正在执行的进程完成了任务或者得到特定的信号而退出,转入僵死状态。这两种进程状态转换完成后,进程主动放弃CPU资源,调用调度函数,选择新的进程来使用CPU。这种情况下,及时的调度在一定程度上可以提高CPU资源的利用率。
  • 220. (3) 对于分时系统,每个进程执行完一定的时间片之后,就必须交出CPU资源,这时,也要发生调度,这样的方案可以保证一定的公平性。 (4) 我们知道,Linux系统提供了两级保护,用户进程可以在用户态和核心态这两种处于不同保护模式的情况下运行,具有不同的特权级别,可以访问的地址空间不同。用户进程可以在这两种模式之间进行切换,用户态通过中断或函数调用就可以转入核心态,其中中断是应进程外部发来的信息的要求而转入核心态,函数调用则是进程内部要求转入核心态。而从核心态切换到用户态,则需要一定的硬件支持。当进程从核心态返回到用户态时,将会调用调度函数,发生调度。
  • 221. 从本质上来看,这些情况可以归结为两类时机,一是进程本身自动放弃处理机发生调度,这包括进程转换到等待和僵死状态,这类调度是用户进程可以预测的;二是由核心态转入用户态时发生调度,这类调度发生最为频繁。系统调用完成和内核处理完中断之后系统是由核心态转入用户态,时间片用完本身也是系统发送的时钟中断,本质上也是一种中断,而可运行队列加入新的进程的工作只能由内核操作完成,无疑是发生于内核态。
  • 222. 4.3.4 进程调度算法 操作系统所采用的进程调度算法取决于系统最初的设计目标,它决定了系统对资源,特别是CPU资源的分配策略,直接决定着系统的特性。Linux系统采用相当简单但效率很高的调度算法,具有很好的响应特性,它提供了三种调度算法:POSIX操作系统标准规定的用于实时进程的先进先出算法(FIFO,First In First Out)和轮转算法(RR,Round Robin),用于普通进程的可抢占式动态优先级算法(Preemptive Scheduling)。
  • 223. Linux先进先出调度算法按照实时进程进入可运行队列的先后顺序,依次把每一个进程投入执行,只有前面的进程执行完成或者自动放弃CPU(比如进入等待状态),下一个进程才可以执行。这样的算法实现简单,在一般意义下也还算公平合理,但是,如果一个执行很短的进程不小心排在一个执行时间很长的进程之后,那就可能要花费比执行时间长很多倍的时间来等待,显然是不可接受的。Linux系统的先进先出算法同时也考虑了进程的优先级,具有相同优先级的进程采用FIFO算法,如果有更高的优先级出现,调度函数就要选择具有高优先级的进程使用处理机,在新进程被加入到可运行队列之后出现的调度时机实际就可以解决这种问题。
  • 224. Linux轮转算法的基本原理是给每一个进入可运行队列的实时进程分配固定大小的CPU处理时间(称为时间片),按照它们在队列中的顺序依次开始执行,如果一个进程的时间片用完之后还没有完成要求的任务,它必须交出CPU的使用权并且重新排到可运行队列的尾部,等待下一次调度,原来排在它后面的进程投入执行。这样的算法,可以保证每个进程就绪之后的等待时间和占用CPU的时间成比例,更加公平。Linux系统使用的RR算法也考虑了进程的优先级,具有相同优先级的进程采用RR算法,而具有更高优先级的实时进程拥有首先使用CPU的权利。这样的方案,可以保证具有高优先级的紧迫型实时进程很快得到响应。
  • 225. 从上面的描述可以看到,Linux提供的实际是软件实时。 Linux系统中,非实时进程的调度采用抢占式动态优先级算法。每个进程拥有不变的静态优先级和可变的动态优先级,调度函数根据各进程的优先级来确定权值,拥有最大权值的进程被选中执行,如果多个进程具有相同权值,则选取排在可运行队列最前面的那一个。每一个进程都分配一定的时间片,时间片使用完之后,系统转入调度函数,等所有非实时进程的时间片都使用完之后,再按照各自的优先级给每个进程重新分配时间片。
  • 226. 时间片是系统中比较关键的一个参数,它的大小直接影响系统的性能。I386系统采用段页式存储管理,进程的切换效率比较低,针对这种情况,Linux 时间片默认值为200ms,用户可以针对不同的进程设置时间片的值。 事实上,Linux系统中并没有根据进程的调度策略分别管理进程,而是把所有可运行进程都集中于同一个队列中,三种调度算法在实现过程中合为一种,使用同一段程序。下一节,我们就来探讨Linux进程调度的具体过程。
  • 227. 4.3.5 进程调度过程 Linux系统的调度过程简洁而高效。整个调度过程大概可以分为五个部分。首先检测中断,如果有中断运行时,调度过程到此为止,直接退出,如果没有中断运行,关中断,在调度的过程中将不再允许中断。其次处理系统的内核例程。然后对当前进程做相关处理:如果当前进程是时间片用完的进程按照轮转法调度,系统重新赋予时间片并把它移到队列的尾部;如果进程因为等待某个事件而转入等待状态引起调度,调度过程中发现事件已经发生,进程仍然转入就绪状态;如果进程处于其他非可运行态的话,就要从可运行队列中删除。这些都是为开始调度而进行的准备工作。
  • 228. 接着调度函数遍历整个可运行队列,从中找到最值得运行的进程,该进程的权值(goodness)最大。如果该进程不是当前进程,系统需要进行进程上下文切换,如果正好就是当前进程,这一部分就可以跳过去。最后打开中断,选中的进程开始执行。 整个调度过程的核心就是如何计算一个进程的权值。在Linux系统中,决定进程权值的相关参数有四个,它们都记录在进程控制块中: (1) policy,策略,一个给定进程采用的调度算法称为该进程的调度策略。进程的调度策略是从父进程那里继承来的,但是也可以通过特定系统调用来改变。
  • 229. (2) priority,优先级,确切地讲是静态优先级。记载了进程最多可以拥有的时间片,从父进程那里继承过来,只能由用户通过系统调用来修改。 (3) counter,计数器,它实际上是进程的动态优先级。它表示进程在当前时间片中剩余的时间量。它的初值等于静态优先级,在进程执行期间,随时间不断减少,当它小于或等于0时,表明进程的时间片用完,重新设置为0,并引起调度。 (4) rt-priority,实时优先级。实时进程的优先级,标志实时进程优先权的高低。取值范围为0~99,取0时表示不是实时进程。
  • 230. 系统在进行调度时,首先确定该进程的调度策略,依据就是policy的值,然后根据不同的策略,选用适当的算法具体计算相应的权值,权值是衡量一个进程是否执行的惟一标准。 衡量实时进程执行的依据就是实时优先级。具体的计算公式为: goodness=1000+rt-priority (4.1) 对于采用实时FIFO策略的进程,具有高实时优先级的进程将一直执行,直到进入僵死状态、进入等待状态或者是被具有更高实时优先级的进程夺去处理机。采用实时RR策略的进程,时间片用完之后,将被放到可运行队列的尾部,等待下一次调度,处理机由下一个具有相同实时优先级的进程使用。
  • 231. 普通进程的调度策略标记为SCHED-OTHER,采用抢占式动态优先级调度策略。选择执行的依据是进程的动态优先级。进程创建之初,动态优先级和静态优先级具有相同的值,随着进程的执行,动态优先级慢慢减小,如果一个普通进程时间片用完的话,它的动态优先级就是0,而且要等到其他所有进程的动态优先级为0时才用静态优先级的值来初始化。这种情况下所有普通进程权值的计算公式都是: goodness=counter+priority (4.2) 因此,在调度中,用完时间片的普通进程被选中的可能性很小,这就给其他进程,特别是新建进程使用处理机的机会。
  • 232. 如果进入调度后,当前普通进程的时间片没有用完,而且仍然位于可运行队列中时,当前进程的权值采用公式(4.3)计算,除了当前进程之外的所有普通进程仍采用公式(4.2)计算权值。 goodness=counter+priority+1 (4.3) 这样,适当增大当前进程的权值,以增加继续使用处理机的可能,可以避免过分频繁的进程切换。 新的普通进程进入可运行队列后,插入到队列尾部,将引起调度,在都使用相同静态优先级的情况下,新进程的权值很大,因此,如果没有实时进程和其他一直未执行过的就绪进程,新建进程投入执行的可能性相当大。可见,Linux系统所采用的这种调度算法优先保证交互性,系统的响应时间比较短。
  • 233. 实时进程和普通进程相比,总是具有更高的优先级。因此,如果可运行队列中同时存在实时进程和普通进程,实时进程总是可以先使用处理机。 权值是Linux系统进程调度过程中选择进程的惟一标准,程序实现非常简单,参看kernel/sched.c。 在讨论进程调度过程的时候,我们始终认为计算机只有一个处理机,实际上,Linux系统很早就开始支持对称多处理器,这种情况下的调度不在本书的讨论范围之内,有兴趣的读者可以参看源代码和本书的相关参考文献。
  • 234. 4.4 小结 调度主要解决处理机资源的分配问题,系统的调度是分层次的,因此也称为分级调度,按照调度发生的频率分为作业调度、交换调度、进程调度和线程调度,分别由不同的调度程序来完成。 Linux系统采用两级调度,用户作业进入内存,直接参与交换调度,进程和线程采用同样的表示和管理方式,也使用同样的调度函数。
  • 235. Linux系统采用请求页式内存动态管理方法,根据进程执行的实际需要分配内存页面并换入内容,同时使用内核交换进程kswapd按照记龄(aging)置换算法来实现页面淘汰功能,内核交换进程周期性地执行,通过缩减page cache和buffer cache、换出SYSTEM Ⅴ共享内存占用的页面、换出或者丢弃其他进程占用的页面等三种途径缩减已使用的内存页面,保证系统中总是有足够的空闲页面,保持整个存储管理子系统高效地运行。
  • 236. 调度函数管理系统的可运行队列,该队列中包括正在执行的进程和所有就绪进程,在实际调度中,调度函数查询每个进程PCB中相关信息,按照一定的算法,在可运行队列选择合适进程,进行进程上下文切换,使得选中的进程顺利执行。Linux系统提供了三种调度算法:POSIX操作系统标准规定的用于实时进程的先进先出算法FIFO、轮转算法RR及用于普通进程的可抢占式动态优先级算法。Linux系统用一个简单的函数实现了这三种进程调度算法,它虽然不十分完美,但高效,确实可以适用于大多数情况。
  • 237. 习题 4-1 什么是分级调度?描述Linux系统的分级调度情况。 4-2 什么是交换调度?其主要功能有哪些?Linux的交换调度有什么特点? 4-3 交换空间是什么?交换区和交换文件有什么区别?如果安装一个用于www服务的Linux系统,你认为交换空间应该怎么设置?为什么? 4-4 进程调度的功能是什么?Linux的进程调度发生在什么情况下? 4-5 Linux系统的实时调度与普通调度有何区别?实时FIFO和实时RR调度算法有何区别?分别如何实现?
  • 238. 4-6 Linux在调度算法实现过程中如何保证系统具有良好的交互性?与此同时,它牺牲了哪些方面的性能? 4-7 如果你是系统的root用户,你将采取什么措施保证你的进程能比别的用户具有更高的或更低的优先权?如果你是普通用户,将采取什么措施?实际操作,能够达到目的吗? 4-8 访问Linux核心代码站点http://www.kernel.org ,了解Linux核心中调度函数的最新进展及新增特点。
  • 239. 第5章 设 备5.1 设备介绍 5.2 数据传输 5.3 I/O软件原理 5.4 小结 习题
  • 240. 计算机系统中所有的软硬件都是由操作系统控制和管理的,其中除了CPU和内存之外的几乎所有硬件通常统称为外部设备。操作系统中设备管理的任务是负责控制并操纵所有的设备,实现不同外部设备之间、外部设备和内存以及CPU之间的数据传输,使它们协同工作,在获得最佳效率、提供良好服务的同时,尽可能地提供统一的用户命令和函数调用接口,对用户屏蔽不同设备之间的差异。 在Linux等操作系统中,所有的设备统一当作文件来处理,称为设备文件,和其他文件一样,这种文件可以使用处理文件的标准系统调用打开、关闭和读写。
  • 241. 操作系统设备管理部分通常也采用分层结构,底层是设备相关部分,直接和相应的设备打交道,负责设备的具体控制,并向上层提供一致的访问接口,通常称为设备驱动程序。上层通常是和设备无关的,这个部分接受来自上层的具体访问请求,并根据实际情况把这些访问请求转向具体的设备驱动程序接口,和设备进行通信,接受驱动程序的执行结果。 本章简要介绍设备管理中数据传输控制的基本原理,并以此为基础,学习设备分配概念及设备驱动程序。
  • 242. 5.1 设备介绍 操作系统中用于设备管理的内核代码在整个内核中是数量最多的部分。外部设备给用户提供进行计算机基本操作以及完成各种特定功能的接口,用户需要交给计算机处理的所有数据都必须通过特定的外部设备来传输到内存和CPU。 设备可以被简单地看作是由机械部分和电子部分组成。在微机系统中,控制器一般都有自己的控制和状态寄存器,独立于系统的内存空间,所有设备的寄存器组成计算机的输入/输出空间(称为I/O空间),操作系统通过设备驱动程序访问I/O空间,管理设备控制器,由控制器具体操纵设备完成预定的任务。
  • 243. 5.1.1 设备分类 外部设备可以按照不同的标准进行分类。从普通用户的角度,按照设备的使用特性来划分,普通微机的外部设备主要包括存储设备和输入输出设备。 从操作系统管理的角度来看,按照设备传输信息的组织形式,外部设备可以划分为字符设备、块设备和网络设备。这也是Linux操作系统进行设备管理过程中的划分方式。 Linux系统中,每一个设备对应于一个设备文件,具有独立的设备号。主设备号描述相应的设备驱动程序,从设备号用来区分同一驱动程序控制下的不同设备实例。
  • 244. 5.1.2 设备实例——磁盘 磁盘是计算机系统中最常见的存储设备,IDE磁盘是现在PC上使用最广泛的硬盘类型,每个IDE控制卡支持两个独立的盘(可以是硬盘、光驱等),每个盘在Linux里表现为独立的块设备。 操作系统本身以及大量的用户数据都存放在磁盘中,同时,Linux系统还使用一部分磁盘空间作为内存交换空间,实现虚拟内存管理。所有实际的磁盘都由多层盘片组成,磁盘的物理结构示意图参看图5.1。磁盘的扇区个数、磁头个数和柱面个数三个数据称为磁盘的基本几何参数。如果知道每个扇区的具体容量(单位扇区容量),整个磁盘的容量就是这三个几何参数和单位扇区容量的乘积。
  • 245. 图5.1 磁盘设备结构示意图
  • 246. 磁盘数据的读写需要一定的时间,这个时间具体由三个部分组成,一是磁头跨越磁道径向移动到要读写道的时间,一般称为寻道时间;二是要读写磁道等待数据移动到磁头位置的时间,称为旋转延迟时间;三是具体读写数据的时间,称为数据传输时间。 在实际的使用过程中,通常把整个磁盘划分为小的管理单元,称为磁盘分区(partition)。在Linux系统中,每一个磁盘分区都可以安装一个独立的文件系统,具有独立的设备号,主设备号对应着磁盘本身,从设备号对应于该磁盘上具体的分区,同时,系统还使用惟一的设备文件来表示磁盘分区,比如设备文件/dev/hda5,hda表示该磁盘的IDE接口上的第1个磁盘(依此类推,hdb、hdc表示该接口上第2、
  • 247. 第3个磁盘等等),对应于主设备号,5是它的从设备号。
  • 248. 5.2 数据传输 数据在外部设备与处理机、内存之间的传输控制,是操作系统设备管理的主要功能,从设备到内存和处理机的数据传输称为输入(input),从内存和处理机到设备的传输称为输出(output),因此数据传输也通常称为数据I/O。一般的PC中,CPU、内存通过系统总线连接在一起,总线定义了所有设备之间通信的协议,各种设备都直接或者间接地连接在总线上,设备和处理机以及内存之间的数据传输必须通过总线来实现。数据传输控制要求能够实现数据在外部设备和内存、CPU之间快速、可靠的传送,充分发挥设备资源的能力,同时使用尽可能少的系统开销。
  • 249. 5.2.1 数据传输控制方式 PC机中常用的数据传输控制方式包括程序直接控制、中断和内存直接访问三种。 1. 程序直接控制 程序直接控制方式就是由用户进程来直接控制内存,或者CPU和外部设备之间的数据传输。用户进程是数据传输的控制者,在进程执行过程中需要传输数据时,通过CPU启动外部设备,继续占用处理机,进入查询测试等待。该进程不停地查询设备是否准备好,一旦数据准备好,完成数据传输,继续下面的执行。
  • 250. 在整个传输过程中,用户进程一直占用CPU,而CPU所做的大量工作是查询设备的状态,因此这种传输方式也称为查询测试方式。如果采用这种方式来传输大量的数据,由于外部设备的速度比CPU要慢很多,因此大量的时间浪费在查询上,设备的利用率可以得到一定程度的保证,但是CPU资源却得不到有效的利用。 2. 中断方式 针对程序直接传输浪费CPU资源的缺陷,引入了中断(interrupt)技术。中断方式要求CPU和外部设备之间有相应的中断请求线,外部设备可以通过中断请求线打断CPU正在进行的工作,转入相应的操作。
  • 251. 中断方式下,当用户进程执行过程中需要数据传输时,通过CPU启动外部设备,自己放弃处理机资源,进入等待状态,外部设备进行相应的数据准备工作,而CPU可以经过调度被其他进程所使用。直到外部数据准备完成之后,设备通过中断请求线发出中断,发生调度,CPU转入中断处理程序,进行相应的数据操作,而等待数据传输的进程被唤醒转入就绪状态,在适当的时候占有处理机,并得到数据继续执行。 利用中断方式,在用户进程等待设备准备数据到发出中断这一段时间内,CPU可以执行其他进程,提高了处理机和外部设备的并行程度,一定程度上解决了处理机资源浪费的问题。但是,如果设备每
  • 252. 一次进行数据传输都只能准备少量的数据的话,系统的效率也得不到有效的提高。每次只传输少量数据,每次都要发生中断,需要进行多次进程调度和进程现场切换,就要耗费大量的CPU资源。同时,如果有多个设备同时进行大规模的数据传输,整个系统中的中断次数会急剧增加,造成CPU无法及时响应中断,出现数据丢失的情况。因此,必须采取一定的措施保证设备在一次中断发生之前进行相当规模的数据传输。 3. 直接内存访问 直接内存访问(Direct Memory Access, DMA)可以用来解决中断方式的上述问题,它在外部设备和内存之间开辟直接的数据通道,设备控制器具有。
  • 253. 更强的功能,可以窃取CPU的一个工作周期,不需要CPU的参与直接把数据放入到内存中指定的位置。 DMA方式传输数据时,正在执行的用户进程通过CPU发出数据传输请求,同时把数据存放地址和数据量这些主要参数通知DMA控制器,用户进程转入等待状态,CPU可以执行其他进程,外部设备不断地窃取CPU的工作周期,把准备好的数据不断地写入内存相应的位置,直到所要求的数量全部完成或者发生错误,才通过中断线通知CPU进行相应的中断处理,这时需要数据的用户进程转入就绪状态,在适当的时间占用CPU继续执行。在整个数据传输过程中,DMA控制器只是获取CPU的工作周期,并不要求它做额外的处理,只是到全部数据传输完成
  • 254. 或者出现错误才发生中断,这样就可以保证使用尽可能少的中断来完成尽可能多的数据传输。 在前两种数据传输控制方式中,数据传输都是围绕CPU开展的,CPU得知设备准备好数据之后,直接控制数据的传输,把它们放到内存中适当的位置,由用户进程使用,二者的差别是CPU获得设备状态的方式不同,前者靠不断地查询,后者是靠设备发送中断请求。而在DMA方式中,数据交换是围绕内存进行的,外部设备和内存之间直接进行数据传输,数据传输过程中不需要CPU的干预,只有数据传输完成之后才通知CPU。
  • 255. 5.2.2 数据传输关键技术 从上面的介绍可以看到,中断技术在整个数据传输过程中占有相当重要的地位,它是提高外部设备和CPU的并行程度、改善系统整体性能的关键。另外一个关键技术是缓冲,利用这样的技术,可以大大地减少外部设备的访问次数,实现系统整体性能的提高。 1. 中断 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序,而转去执行相应的事件处理程序,待处理完毕后又返回原来被中断处,继续执行或者调度新的进程执行的过程。引起中断发生的
  • 256. 事件称为中断源,在计算机系统中,外部设备数据传输过程中发生的中断属于I/O中断,是中断源中的一大类,其他中断源有周期性的时钟中断、电源掉电产生的中断等等。中断源向CPU发出的请求中断处理信号称为中断请求,而CPU收到中断请求后转入相应的事件处理程序称为中断响应。 按照中断源产生的位置,中断分为内中断和外中断。内中断由处理机和内存内部产生,通常也称为陷阱,它包括程序运算引起的各种错误和分时系统中的时间片中断等等。外中断由处理机和内存之外的设备发出,包括上面讲到的I/O中断和时钟、电源中断等等。
  • 257. 并不是所有中断请求都会得到及时的响应。很多情况下,比如系统正在进行进程调度或者内存调度操作,为了保证操作的封闭性,这时不允许CPU响应中断,这种情况称为禁止中断或者关中断。CPU禁止中断,完成必要的操作之后必须通过硬件重新设置才能够接收中断,这个过程称为开中断。 关中断之后,CPU不接受任何中断请求。另外一种情况是CPU可以有选择地响应某些中断,称为中断屏蔽。中断屏蔽是指中断请求产生之后,系统用软件方式有选择地封锁部分中断,而允许其余部分中断仍然能够得到响应。 并不是所有中断请求都具有平等地得到响应的权利,根据中断源的紧急程度,操作系统对不同的中断请
  • 258. 求赋予不同的优先级。如果两个中断请求同时发生,优先级高的中断有权在优先级低的中断之前得到响应。各种中断源的优先级在系统设计时设置完成。 而CPU收到中断请求后,首先要进行进程切换,原来正在执行的进程放弃处理机,保护现场完成之后,转入相应的事件处理程序,进行中断处理。 一台PC机中断号的个数是有限的,在Linux系统中,中断号当前使用情况记录在文件/proc/interrupts中。如果安装了很多设备,大家就必须采取一定的措施来共享有限的中断号资源,称为中断共享,实现中断共享需要设备和中断处理程序两个方面的支持,一方面CPU能够通过询问设备而知道该设备是否产生过中断,另一方面中断处理程序能够向前传递别的设备产生的中断信号。
  • 259. 2. 缓冲 缓冲是计算机系统中为了解决外部设备和CPU之间处理速度的匹配问题,减少外部设备中断请求次数而设置的暂时存放数据的区域。 根据数据传输控制方式,可以有两种实现方式。一是采用硬件缓冲器,在外部设备中设置缓冲,外部设备每次传输数据之前,可以利用缓冲器准备更多的数据,提高每一次传输的数据量,减少传输的次数。可以想象,如果某个设备每次只准备一个字节,传输1KB数据需要发生一千多次中断请求,即便是DMA方式,也需要一千次获取CPU工作周期,每次传输都要获取总线使用权,对其他进程的影响会是很大的。如果该设备设置1KB大小的缓冲器,可
  • 260. 以先把数据都准备在缓冲中,然后只需要一次中断,一次性掌握CPU和总线就可以完成数据传输,系统的效率可以得到明显的改善。另一种方法是在内存中划分专用的数据缓冲区,所有的数据I/O都要经过这些缓冲区,每次发生数据传输后并不清除缓冲区中数据,下一次访问数据时首先在缓冲区中查找,如果缓冲区中有,则不需要启动外部设备就可以得到需要的数据,如果缓冲区中没有需要的数据,再启动设备。这样,经过一段时间的积累,经常访问的数据基本都在缓冲区中,系统启动设备的次数就大大降低,可以提高数据I/O的整体效率。 前一种实现方法主要是设备的硬件本身增加了缓冲器,属于硬件缓冲,后一种方法则主要由操作系统
  • 261. 来实现,称为软缓存。在Linux系统中,I/O过程中使用了多种缓冲区,其中最主要的是由文件系统来管理,用来实现块设备I/O的块高速缓冲区,第6章“文件系统”中,将结合块高速缓冲区进一步讨论缓冲技术的实现和管理。 5.3 I/O软件原理 I/O软件是控制外部设备与内存、处理机进行数据交换的所有软件的通称。其主要的任务是充分发挥各种设备的作用,屏蔽各种设备的特殊性,在保证系统具有较高的整体性的同时,尽可能向用户提供一个友好、清晰、规范和设备独立的配置及使用界面。 计算机系统的I/O软件也同样具有层次结构。
  • 262. 5.3.1 Linux系统I/O软件层次结构 操作系统中I/O软件大多数都可以看作是分层结构,图5.2给出了Linux系统I/O软件层次结构示意图。
  • 263. 图5.2 Linux系统I/O软件层次结构示意图
  • 264. 在Linux系统中,I/O软件和文件系统是紧密联系的,文件系统提供了用户访问设备、进行数据I/O操作的一致性接口,这个部分是设备独立的,用户可以采用统一的方式访问不同的设备,文件系统中实现了设备管理的设备无关性。 在Linux系统中设备都是按照文件的方式命名的,每一个设备是一个特殊类型的文件,从用户使用的角度来看,对设备的访问也等同于对文件的访问,具体的设备操作由文件系统根据情况映射到具体的设备驱动程序来完成。所有的设备都采用和文件相同的访问权限控制方法,这种访问权限的控制和用户联系在一起,有效地实现了设备的保护和设备数据的保密。
  • 265. 缓冲区管理和设备分配也是由文件系统完成的。这里的缓冲区主要指内存中开辟的软缓冲区,它是关系到整个系统效率的关键技术之一。对于系统中的磁盘等共享设备,可以在文件系统的管理下同时为多个用户服务,而对于打印机等独占设备,则属于临界资源,某一个特定时刻通常只能为一个用户提供服务,这两种不同类型的设备必须分别采取不同的分配方式。 处理和管理硬件控制器的软件是设备驱动程序。在Linux系统中,每个设备驱动程序都是内核的一部分,它们提供设备与系统引导程序的接口,可以在启动过程中对设备进行初始化,还提供面向设备无关部分的接口,接受上层设备无关软件的I/O请求,
  • 266. 最后通过向下的设备控制器接口,采用查询或者中断方式操纵设备控制器,来和具体设备进行数据传输。Linux系统的设备驱动程序通常可以采用模块(modules)的方式来设计,在系统引导完成之后,可以动态地加载或卸载,5.3.2节将介绍这方面的知识。 除了少量使用查询方式的设备之外,计算机系统中大多数设备都利用中断来控制数据的传输。中断发生之后,CPU将保存现场并切换到中断处理程序。一般情况下,中断处理过程中不允许再响应其他中断,至少不能响应具有相同、或者更低优先级的中断,为了不影响其他中断的正常响应,中断处理过程必须要尽可能快地完成。
  • 267. 实际上,要保证每一个中断处理程序都很快执行完是不太现实的。Linux采用了一种特殊的方式来实现中断处理的快速完成,称为底半(bottom half)处理的技术。每一个中断处理程序,实际上都可以划分为两个部分——一个部分响应中断请求,传输相关数据,通常只是中断处理工作中很小的一部分;另一个部分处理和发生中断的设备相关的各种数据结构,解决设备状态信息和操作模式的转换等各种善后工作,这个部分通常要和设备进行通信,需要更多的时间。根据中断处理程序的这种特点,Linux系统中把一个中断处理分隔为两个部分:快速的上半部分(top half,顶半)和慢速的下半部分(bottom half,底半)。顶半只处理很少一部分
  • 268. 工作,通常负责处理硬件发出的请求,解决数据传输问题,必须快速执行,尽可能保证在下一个中断产生之前完成。底半处理该设备相关的数据结构和设备状态控制信息等比较费时的工作,时间方面的要求不很高,同时也允许响应其他中断请求。 因此,Linux中断处理程序可以分为顶半和底半两个部分,中断发生之后,中断处理的顶半首先快速执行,处理完成之后就可以接受其他中断,剩下的底半部分放到一个特定的队列中,由内核提供的特殊机制负责在适当的时机统一执行。这样,既可以保证中断处理程序的完整性,又可以快速响应其他中断,保证系统具有良好的响应特性。
  • 269. 当一个用户进程发出I/O请求之后(比如,在用户进程中执行了一个设备读取的函数调用,这个I/O请求直接发送给文件系统),文件系统根据函数调用参数确定需要读取的设备,先进行设备访问权限的检验,如果合法则继续进行,否则就返回错误信息。文件系统为这个读取工作申请适当的缓冲区,如果发现需要的数据在缓冲区中已经存在,直接从缓冲区中读取数据,向用户进程返回I/O应答,整个读取过程完成。
  • 270. 如果缓冲区中没有需要的数据,文件系统根据情况进行设备分配,向下层的设备驱动程序发送具体的读取请求。驱动程序利用上层传来的数据信息,操纵设备控制器读取数据,发出读取命令后进入等待状态,设备则进行具体的数据准备工作,CPU则可以转向其他进程。外部设备数据准备完成之后,发出中断请求,转入中断处理程序完成负责中断响应和数据传输的顶半部分,中断处理的底半部分在适当的时候再由内核去完成,唤醒设备驱动程序把数据放入相应的缓冲区中,返回缓冲区状态给文件系统。然后由文件系统从缓冲区中读取数据给用户进程,返回I/O应答。
  • 271. 在设备读写过程中,比较慢的是设备和内存之间进行数据交换的过程,特别是设备准备数据的过程,而从缓冲区中读取数据是内存不同位置之间的数据传输,速度要快得多。对于经常访问的设备,要读取的内容已经在缓冲区中的情况占绝大多数,因此通过缓冲区的使用,外部设备读写的效率可以得到很大的提高,当然,这种效率是以系统本身的复杂性为代价的。
  • 272. 5.3.2 Linux设备驱动程序 设备驱动程序是设备管理的主要软件之一,它负责控制各种设备,是向文件系统提供一致性界面的关键层。每个设备都必须由特定的设备驱动程序来管理,由于设备本身种类繁多,性能各异,造成了系统中设备驱动程序也有很多种类,驱动程序代码占整个系统内核代码的大多数。但是这些针对不同设备的驱动程序都使用基本相同的接口与内核其他部分通信,设备的特殊性在这个层次中深深地隐藏起来,这给用户以及系统其他部分使用和管理设备带来了极大的方便。
  • 273. 在第1章学习操作系统基础知识的时候,曾经介绍过,Linux内核基本采用模块结构,不同的内核子系统按照模块来构建,作为一个整体存在于系统内存中,属于单内核(或宏内核)模式,这使得系统具有相当高的运行效率,但是系统的可扩展性及可移植性受到一定的影响。与之相对应的是微内核模式,微内核中大部分内核模块都作为独立的进程,它们之间通过消息通信,模块之间互相提供服务。
  • 274. 采用微内核模式的操作系统中,用户可以方便地添加新的组件,实现设备驱动等新的功能,相对来讲,单内核模式中添加新组件要困难得多。Linux 系统采用模块(modules,也称为模组)技术,来支持动态装载和卸载的模块,动态装载或卸载时甚至不需要重新启动计算机。利用模块技术,就可以方便地在单内核结构中添加新组件或卸载不再需要的内核组件。 每一个模块都是核心的一部分,都运行于系统态,和其他内核部分具有相同的权限,因此,有漏洞的模块会给系统的性能和稳定性带来不利的影响,而恶意的模块就可能成为一个逻辑炸弹或病毒的良好载体,对系统的安全造成威胁。
  • 275. 除了系统启动过程中所必须的设备(如键盘、磁盘设备等)之外,其他大多数设备以及伪设备(网络设备、文件系统等)的设备驱动程序,都是采用模块方式来管理的。在系统启动完成之后,系统管理员可以利用相关的命令来查看、加载、卸载各种驱动程序模块。 Linux设备驱动程序基本结构 早期,Linux系统支持的设备驱动程序大多数是业余高手们开发的,随着Linux的不断发展,越来越多设备生产厂商也开始提供驱动程序。所有驱动程序都是内核的一部分,驱动程序的结构和接口都有相当规范的定义。
  • 276. 给Linux写设备驱动程序是一件相当容易的事,而且很多人都在做这样的工作,这里不打算介绍具体的开发过程,这方面的资料网上很多。如果某一天,你发现你的某一个设备无法驱动,首先应该到网上去找找,说不定有人碰到和你同样的问题,而且已经写好了这样的驱动程序,实在不行,自己动手花一两天时间,应该就可以完成了。这里只简单介绍驱动程序的基本结构。 根据图5.2所示的I/O软件结构图,设备驱动程序向下的接口是面对设备控制器的,它定义了驱动程序如何与设备进行通信的协议;向上面对的是文件系统,它通过文件系统为内核其他部分提供统一的接口,用户的设备操作通过文件系统来映射到具体的
  • 277. 设备驱动程序,这一部分接口对于所有设备驱动程序几乎都是相同的;此外,还应当提供与系统引导的接口,这是在系统启动过程或者加载设备驱动模块时,初始化设备所必需的。 一个完整的设备驱动程序通常包括五个部分:设备驱动程序的注册与注销、设备的打开与释放、设备的读写操作、设备的控制操作,以及设备的中断或者查询处理。
  • 278. 驱动程序的注册是在系统初始化或驱动程序模块加载时完成的,主要实现设备的初始化准备工作,与之对应,驱动程序注销是在系统关闭或者驱动程序模块卸载时完成,二者属于设备驱动程序和系统引导的接口。注册之后,同时也就建立了和文件系统的接口,文件系统根据注册过的资料,就可以建立文件操作与具体设备驱动程序的映射关系。 和普通文件类似,设备首先要打开才能够进行读写操作,而且完成操作之后也要及时地释放,释放设备私有数据占据的内存、关闭设备等等,以确保下次可以正常打开和使用设备。在设备驱动程序这个层次上,这些操作针对不同的设备要由不同的函数来完成。
  • 279. 在读写过程中,设备可能采用查询或者中断的方式来控制数据传输,针对不同的数据传输控制方式,驱动程序采取不同的管理方式实现具体的数据传输。
  • 280. 5.4 小结 本章介绍了Linux设备管理方面的基础知识。在Linux系统中,根据系统管理方式的不同,设备可以分为字符设备、块设备和网络设备三类,所有的设备基本都是按照特殊的文件——设备文件来对待。因此,在操作系统使用过程中,设备的特殊性都为文件系统所屏蔽,用户命令、系统调用,以及内核其他部分只能通过文件系统,以统一的模式来使用设备。
  • 281. 可以使用不同的方式控制外部设备、CPU和内存之间的数据传输,PC机通常使用的方式有程序直接控制(查询)、中断,以及内存直接访(DMA)。 提高数据传输效率的另一个有效手段是缓冲,可以在设备上增加缓冲器,设备每次传输数据之前可以准备更多的数据,扩大设备与CPU或内存之间一次数据传输的规模,减少中断次数,称为硬缓冲,这种方法增加了硬件设备的成本和复杂度。也可以在内存中开辟缓冲区,设备与CPU或内存之间的数据传输都通过这样的缓冲区保留备份,下一次用户进程需要数据传输时首先在缓冲中寻找,如果已经存在于缓冲中,就不需要再启动外部设备,从而节约了大量的时间,这种方式称为软缓冲,在Linux系统中统一由文件系统管理。
  • 282. I/O软件是控制外部设备与内存、处理机进行数据交换的所有软件的通称。Linux系统的I/O软件具有层次结构,上层是文件系统,它负责设备命名、设备保护、缓冲区管理以及设备分配等工作,屏蔽各种的设备特殊性,向用户提供一个友好、清晰、规范和设备独立的配置、使用界面,用户可以像使用普通文件那样进行设备操作;下层主要是设备驱动程序和对应的中断处理程序,Linux系统中大多数设备驱动程序都是独立的内核模块,可以动态地加载和卸载,同时采用独具特色的底半处理技术来完成中断处理,提高中断处理的效率。 层次构造的Linux系统I/O软件中,所有模块协同工作,可以充分发挥各种设备的作用,同时保证系统具有较高的整体性。
  • 283. 习题 5-1 数据传输控制方式有哪几种?比较它们的优缺点。 5-2 什么是中断、中断处理和中断响应?为什么要引入中断? 5-3 在你的机器中,键盘和CPU、内存之间的数据传输使用什么方式控制?如果有一次计算机不再响应任何键盘命令,你认为是什么原因?有办法解决吗? 5-4 什么是缓冲? 为什么引入缓冲? 5-5 在Linux系统中,为什么我们可以像使用文件一样操作一个设备?
  • 284. 5-6 Linux文件系统在整个I/O软件中处于什么地位? 5-7 什么是设备驱动程序?Linux系统中,用户怎么使用设备驱动程序? 5-8 下面各项工作是在I/O软件的哪一层完成? (a) 磁盘写操作、计算磁道、扇区和磁头 (b) 维护磁盘读写高速缓冲 (c) 读取设备状态寄存器 (d) 检查用户是否可以访问某个设备 5-9 如果你新装的声卡不工作,你如何解决这个问题?
  • 285. 第6章 文件系统6.1 文件系统概述 6.2 文件管理 6.3 目录 6.4 逻辑文件系统——Ext2 6.5 虚拟文件系统——VFS 6.6 小结 习题
  • 286. 数据处理是计算机的主要功能之一,与数据处理相关的数据管理和数据保存是必不可少甚至是较为重要的环节。在计算机中,大量的数据和信息是通过文件存储和管理的。文件系统负责管理文件和逻辑文件系统,提供管理设备、屏蔽设备复杂性的手段,为系统内核其他部分、用户命令和系统函数调用提供统一的服务接口。 本章主要讨论Linux系统中文件的概念、 目录结构及访问权限,Linux的逻辑文件系统Ext2, 虚拟文件系统VFS, 文件系统管理及缓冲区管理等内容。管道(FIFO)文件是利用文件系统作为接口实现进程间的通信,本章不再介绍,具体原理请参见2.2.6“进程通信”部分。
  • 287. 6.1 文件系统概述 通常我们把与管理文件有关的软件和数据,统称为文件系统。它方便地组织管理计算机中的所有文件,为用户提供文件的操作手段和存取控制。同时,文件系统隐藏了系统中最为纷繁复杂的硬件设备特征,为用户以及操作系统的其他子系统提供一个统一、简洁的接口,通过文件系统,使得用户方便地使用计算机的存储、输入/输出等设备。
  • 288. 在学习Linux进程管理时,我们也许注意到,系统惟一感知和控制进程的关键数据——进程控制块中,除了CPU和内存资源之外,只包含了文件系统信息和文件信息,而没有设备的任何信息,这就是文件系统所起的作用。 Linux系统中把CPU、内存之外所有其他设备都抽象为文件来处理。进程只和文件系统打交道,具体的细节,由设备管理部分具体实现并为文件系统提供尽可能简洁统一的接口。因此,文件系统还同时充当着设备管理接口的角色,用户进程使用和操作具体的设备,都必须通过文件系统进行。文件系统是操作系统中与管理文件有关的所有软件和数据的集合。
  • 289. 不同的操作系统可能采用不同的文件系统。支持多种不同类型的文件系统是Linux操作系统的主要特色之一。Linux系统自身的文件系称为ext2,它也是Linux默认的文件系统。我们把ext2以及Linux支持的文件系统称为逻辑文件系统, 通常每一种逻辑文件系统服务于一种特定的操作系统,具有不同的组织结构和文件操作函数,相互之间差别很大。Linux在传统的逻辑文件系统的基础上,增加了一个称为虚拟文件系统(VFS)的接口层,如图6.1所示。
  • 290. 图6.1 Linux文件系统层次结构示意图
  • 291. 系统中所有的设备,包括字符设备、块设备和网络设备,都按照某种方式由逻辑文件系统统一管理,逻辑文件系统为它们提供访问接口。虚拟文件系统在最上层,管理各种逻辑文件系统,屏蔽了它们之间的差异,为用户命令、函数调用和内核其他部分提供访问文件和设备的统一接口, 使得不同的逻辑文件系统按照同样的模式呈现在使用者面前,对于普通用户来讲,觉察不到逻辑文件系统之间的差异,可以使用同样的命令来操作不同逻辑文件系统所管理的文件,可以在它们之间自由地复制文件。
  • 292. 6.2 文件管理 6.2.1 文件 文件可以简单地理解为一段程序或数据的集合。在操作系统中,文件被定义为一个命名的相关字符流的集合,或者一个具有符号名的相关记录的集合。符号名用来惟一地标识一个文件,也就是文件名。Linux系统中,文件名最大长度由NR-NAME-LEN控制,默认值为255个字符。 文件定义中所指出的不同基本组成单位表示了两种形式的文件。相关字符流组成的文件是一种无结构文件或流式文件。相关记录组成的文件称为记录式文件。记录式文件通常主要用于信息管理。
  • 293. 在UNIX、Linux等操作系统中,把包括硬件设备在内的能够进行流式字符操作的内容都定义为文件。 Linux系统中文件的类型包括:普通文件,目录文件,连接文件,管道(FIFO)文件、设备文件(块设备、字符设备)和套接字。 Linux系统把文件按照其性质、用途等标准划分为不同的类别。操作系统根据文件的类型处理文件。按照用途,文件可以分为:系统文件、库文件和用户文件。系统文件直接和操作系统本身有关,包括操作系统核心和各种系统应用程序和数据;库文件通常指系统提供给用户调用的各种标准过程、函数和应用程序;用户文件是用户委托计算机文件系统管理的文件。
  • 294. 当然,这只是一种相对的标准,对于Linux系统,根据自己的实际需要,具有特殊权限的用户(系统管理员)可以重新修改并编译升级整个内核,这个过程将会修改大部分系统文件,同时库文件也可以按照自己的需要添加和修改。 根据文件中数据的表示形式,可以把文件划分为ASCII码文件和二进制文件。 按照文件操作过程中的保护级别,文件可以划分为只读文件、读写文件、可执行文件,Linux操作系统通过这样的方式来控制文件的访问权限。按照文件中信息流向还可以把文件分为输入文件、输出文件和输入/输出文件。按照文件在系统中的存在时间,可以把文件分为临时文件和永久文件。
  • 295. 6.2.2 文件结构 系统使用者关心的只是如何方便地组织和使用文件,即文件的逻辑结构,而系统的设计者则更关心文件具体的实现方式,也即文件的物理结构。 1. 文件逻辑结构 文件的逻辑结构是用户可见结构,即从用户角度观察到的文件系统。从逻辑结构来看,Linux系统的文件采用的是字符流式的无结构文件。 用户通过对文件的存取访问来完成对文件的各种操作,常用的访问方式包括顺序方式和随机方式。Linux系统同时支持顺序和随机两种访问方式。 用户对文件的操作只能通过操作系统提供的命令接口或者函数调用接口。
  • 296. 2. 文件物理结构 文件的物理结构指的是文件在存储设备上的组织方式,即一个文件在具体设备上的实现方法。外部存储器也按照一定的规则划分为小的物理单元,称为块,每个块大小相等,相应地,文件信息也划分为和外存物理块相等大小的逻辑块。对于无结构文件来讲,文件本身没有特定的逻辑结构,最小的单位是字节,可以很方便地划分为逻辑块。 文件的物理结构通常解决文件的逻辑块与物理块之间的映射关系,也即一个文件对应的物理块的具体组织方式。常用的文件物理结构有顺序、串联、索引和多重索引等方式。
  • 297. (1) 顺序方式 顺序方式按照逻辑上的连续关系把文件依次存放在连续的物理块中。如图6.2所示,文件逻辑块和物理块之间是最简单的线性关系,因此很容易实现,也可以相当方便地实现文件的顺序和随机访问,只要确定了文件头的位置和文件长度,一切操作都可以快速实现。但是,这些优势只有在文件能够一次性写入的情况下才存在。由于文件建立时并不知道文件的长度,系统无法确定该给这个文件分配多少个物理块。而且,这种方式也容易造成磁盘碎片。
  • 298. 图6.2 顺序方式文件示意图
  • 299. (2) 串联方式 串联方式的结构采用链表来实现,每一个物理块分为两个部分,一部分用于存放数据,另一部分存放一个指针,指向后续连接的下一个物理块。存放同一个文件的物理块不需要连续,整个文件的连续性由链表的指针来保证,如图6.3所示。这种方法几乎可以利用每一个物理块,没有连续方式那样的碎片问题,可以实现文件的动态增长,也可以在文件中任何一个部位增加和删除内容。文件的顺序访问也可以方便地实现,但是随机访问的实现变得很复杂。
  • 300. 图6.3 串联方式文件示意图
  • 301. (3) 索引方式 索引方式为每一个文件建立一张索引表,表中存放文件的逻辑块与物理块之间的对应关系。也就是把串联方式中每一个接点所记录的链表指针信息统一保存在一个索引表中,如图6.4所示。这使得文件的非连续存放、文件动态增长、方便的文件内部修改等串联方式的优点都保留了下来,同时,也能够方便地实现文件的随机访问。如果把整个索引表保存在内存中,整个文件的访问效率也可以大幅度提高。这种方案的问题在于索引表的处理。连续方式、链表方式、索引方式都可以用来解决索引表的存放,比较好的方案是索引方式。
  • 302. 图6.4 索引方式文件示意图
  • 303. 实际中,很多操作系统采用一种称为多重索引的物理结构,同时使用单级索引和多级索引。每个文件由一张索引表描述,表中一部分内容直接指向物理块,称为直接块。索引表中同时还包含一部分二级索引指针,指向新的索引表,类似的,文件索引表中还可以包括三级甚至更高级的索引指针,提供更多的间接块。对于比较小的文件,可以直接存放在一次间接块提供的空间中,而对于较大的文件,才使用多次间接块。这种方式的缺点一是索引表本身占用存储空间,二是每次访问数据都需要先访问索引表,需要更多的系统时间开销。只要索引表设计合理,能够保证正常使用的大多数都只利用直接块,还可以把索引表放在内存中,保证系统的访问效率。
  • 304. 这种方式基本上保证了文件的动态可变,实现了文件高效率地顺序和随机访问,Linux系统文件的物理结构采用的就是多重索引方式,见图6.5。
  • 305. 图6.5 多重索引方式文件示意图
  • 306. 6.2.3 Linux文件 Linux系统的文件是无结构的流式文件,文件的物理结构采用易于扩展的多重索引方式,便于文件动态增长,同时也可以方便地实现顺序和随机访问。基于字节流的概念,Linux系统把目录、设备等都当作文件来统一对待。Linux默认的是Ext2逻辑文件系统。
  • 307. Ext2文件系统中的所有文件都采用i节点(i-node)来描述,每一个文件、目录或者设备都对应于一个且只能对应于一个i节点。每一个i节点包含两个部分的基本参数:文件说明信息和索引表。根据所存放的位置,i节点又可以分为磁盘i节点和内存i节点,分别使用数据结构ext2-inode和ext2-inode-info来描述。其中磁盘i节点静态存放在外部存储器,包含了整个文件的完整说明信息和物理块分布情况,而内存i节点是为了减少设备存取次数、提高文件访问效率,在内存中特定区域中建立的磁盘i节点的映像。
  • 308. 磁盘i节点文件说明信息包括文件名称、类型、文件长度、所占用的物理块数、创建和最近一次访问时间等基本信息,以及链接数、拥有者用户名、用户组名以及存取控制表等与文件共享、保护和保密相关的信息。每一个i节点的索引表前12个项记录文件直接物理块的位置,后面3项分别是间接、二级间接和三级间接物理块索引,这样的方式既可以保证小文件能够快速存取,又可以适应大文件存储扩展的需要。Ext2文件系统物理块的大小可以是1024、2048或者4096字节,在初始化文件系统的时候由用户指定,默认值是1KB,块地址占4字节,因此每个物理块可以存放256个块的地址,这样,如果把一个i节点所有的物理块放满,得到最大的文件应该是:
  • 309. 直接块+间接块+二次间接块+三次间接块 即: 12KB+256KB+64MB+16GB 实际上,在32位PC上的Linux系统中,寻址范围32位,文件最大最多只能达到4GB。 如果一个文件的内容小于等于12个块,物理块采用默认值时是12KB,就可以全部使用直接块来存放,能够保证相当高的存取效率。i节点具体结构可以参看图6.5。 内存i节点除了包含磁盘i节点的说明信息之外,还增加了当前文件打开状态信息。
  • 310. 6.3 目录 每一个文件系统都提供目录来记录文件的有关信息,在包括Linux在内的很多操作系统中,目录本身也是一种文件,可以按照文件进行管理,在Linux中称为目录文件。利用目录的层次结构,可以对系统中的文件方便地进行分隔管理,实现文件的快速搜索,解决文件之间的命名冲突,同时也可以提供文件共享的解决方案。
  • 311. 6.3.1 目录结构 最简单、最原始的结构是单级目录如图6.6(a) 。这种结构实现简单,可以实现文件系统空间的自动管理。但是,这样的结构中,用户必须保证每一个文件的名称在整个系统中惟一。系统要访问某一个文件,必须在整张目录表中搜索,效率也较低。一个直观的扩展方式是采用两级目录结构,根目录下面可以存放文件,也可以存放下一级目录(称为子目录),子目录下面存放文件,如图6.6(b)。 进一步推广这种层次关系,就形成了多级目录结构,每一级目录中都存放所属文件和下一级目录的信息,整个目录层次结构形成一个完整的目录树。如图6.6(c)。
  • 312. 图6.6 文件目录结构类型
  • 313. 树形的多级目录结构,可以更好地解决文件命名冲突问题。同时,文件系统用一个树状结构表示,根据文件不同的类型、不同的拥有者以及不同的保护要求,可以划分为不同子树,方便地实现文件的管理,在这种树形层次结构中,文件的搜索速度也更快。几乎所有的操作系统都采用树形的多级目录结构。
  • 314. 在树形的多级目录系统中,文件名由路径名给出,路径名惟一确定一个文件在整个文件系统中的位置,可以有两种方式来表示文件的路径。一种是绝对路径名;另外一种方式是从当前目录开始,指定文件相对于当前目录的位置。当前目录是指用户当前在目录树中所处的目录位置,也称为工作目录。例如,在Linux系统下有路径/home/dy/linux/kernel/sched.c,路径的第一个字符是Linux系统的分隔符“/”,代表从根目录开始,是一个绝对路径,这个路径表明在根目录下有home目录,而home下又有dy子目录,一直到最后的文件,文件的名称为sched.c。如果当前用户的工作目录是/home/dy/linux/,这时相对路径kernel/sched.c所指得就是文件/home/dy/linux/kernel/sched.c。
  • 315. 和大多数支持多级目录的操作系统一样,Linux系统每一个目录下面都有两个特殊的目录项“.”和“..”,前者指当前目录,而后者指当前目录的上一级目录。对于上面的例子,当前目录是/home/dy/linux/,相对路径 ./kernel/sched.c和kernel/sched.c具有相同的含义,而 ../指的就是/home/dy,因此,../linux/kernel/sched.c也是指/home/dy/linux/kernel/sched.c。
  • 316. 6.3.2 访问权限 对于普通文件、目录以及具体的设备,都存在一个访问权限(也称为存取权限)控制问题。 文件存取权限即文件读、写和执行的许可权,它和文件的共享、保护及保密相互联系、密不可分。 文件的共享是指不同的用户共同使用一个文件。共享和由此带来的安全性问题是一对矛盾,每一个操作系统都必须在二者之间找到一个平衡点。所谓安全性,通常包括保护和保密两层含义。
  • 317. 1. 文件共享 文件共享指允许多个用户共同使用一个文件。文件系统一般都提供文件共享方法,使得只要保存某个文件的一个副本,就可以实现多个用户在不同目录下共同访问这一副本。 系统中实现共享最简单的方法就是不同的用户使用相同的绝对路径名来访问同一个文件,这种方法中,所有用户使用同样的名称来访问共享文件。如图6.7(a)所示,可以看出,这种方法的主要缺陷是需要访问多级目录,多次访问外部存储器,效率低。
  • 318. 图6.7 文件共享方式示意图
  • 319. Linux等操作系统还提供了更为简洁的链接法来实现共享。在需要访问共享文件的地方建立一个特殊的链接文件,直接指向共享文件,链接文件和原共享文件可以具有不同的名称,链接文件名也称为原共享文件的别名,它们都指向相同的文件内容,访问链接文件就是在访问共享文件本身。如图6. 7(b)所示。这种方法具有更高的效率,但原本完整的树状文件系统,经过链接之后变成了网状结构,一部分文件的路径不惟一,也带来一定的管理开销,在Linux系统中,链接文件作为一种单独的文件类型来对待。
  • 320. 2. 访问权限控制 文件的共享、保护和保密都涉及到文件访问许可权限的问题,针对不同的需要,系统可以采用多种不同的方式来控制文件的存取权限。 (1) 口令方式 在文件创建的时候,文件拥有者可以为每一个文件设置访问口令(password),访问口令被记录在文件说明信息中。文件系统在用户试图访问该文件的时候,首先要求用户提供口令并与文件说明信息中记录的口令进行比较,使用者必须提供正确的文件访问口令才能够存取该文件。通过这样的方法,可以简单地实现文件的共享与保密。口令验证的过程比较简单,只是保密性能相对比较差。
  • 321. (2) 密码方式 密码(encryption)在文件创建的时候,文件拥有者在文件写入存储设备之前,通过特定的算法和加密密钥对文件内容进行编码加密,而在读取文件的时候,必须提供相应的解密密钥进行译码解密。加密和解密可以采用相同或不同的密钥,只有确切知道解密密钥的用户才能够读出被加密的文件。 口令方式中有时也采用一定的加密技术。加密口令方式只是对口令本身加密,加密后的口令仍然存放在文件说明信息中,而密码方式是对整个文件进行加密,加密时采用的密钥掌握在用户自己手中,因此,密码方式的保密性强,但是要耗费大量的处理时间。
  • 322. 上面两种文件存取权限控制方法是针对特定文件的,在多用户系统中,还可以针对特定的用户进行文件存取权限控制。大多数系统,包括Linux,用户身份验证都采用用户口令方式,建立用户的时候,设置其口令,口令以加密的形式存放在系统中,每次用户登录都要提供口令,与系统中存放的数据进行比较,如果相同,用户登录成功,否则,拒绝用户登录。在这样的系统中,多个用户可能同时使用计算机,每个用户都拥有自己的文件,这些文件的存取使用控制权由用户拥有。
  • 323. (3) 存取控制矩阵 存取控制矩阵是一个二维矩阵,其中一维是系统中所有的用户,另一维是系统中所有的文件,矩阵的每一个元素都表示该元素对应的用户对文件的存取控制权限,如图6.8所示。当用户对某个文件进行操作时,系统查找矩阵中该用户和该文件所对应的元素的值,只有当该元素表明有访问许可时,才可以进行具体的访问。 利用这样的矩阵,可以对系统中所有文件的存取权限进行完整有效的控制。但是对于规模比较大的系统,存储和管理这样的矩阵需要比较大的系统开销。 用户对每一个文件的访问,都要对矩阵的一行进行搜索,整体的效率比较低。
  • 324. 图6.8 文件存取控制矩阵示意图
  • 325. (4) 存取控制表 存取控制表是针对某个特定文件,把文件拥有者和相关的用户按照某种关系划分为类,按照不同的用户类赋予用户文件存取权限。Linux系统中,文件的存取权限分别赋予文件拥有者、拥有者所在用户组和其他用户组这三类用户,每一类访问的权限设置三位,分别为读、写和执行,这样就相当于每个文件只需要记录9位数据就可以进行权限控制了。 实际上,每一个文件的存取控制表都相当于是整个存取控制矩阵中的一行元素。存取控制矩阵中的每一行对应于一个文件,首先去掉空元素,然后把所有的用户按照文件所有者、所有者所在组和其他用户组简化之后,就可以得到该文件的存取控制表。
  • 326. 在Linux系统中,每一个文件都在文件说明信息中保存着自己的文件存取控制表,只有符合存取控制表中规定的条件,才允许进行具体的访问。 对设备文件的权限设置实际上是限制了用户对设备本身的操作。 设置文件访问口令和文件加密属于文件级的访问权限控制。在多用户系统中,必须要进行用户验证,文件系统针对特定的用户,可以通过存取控制矩阵或存取控制表来设置对文件的存取权限,这类方法可以认为是基于用户身份的存取权限控制,属于用户级的访问权限控制。
  • 327. 在这些控制方法中,不论是口令还是密钥,都可以归结为口令。文件的存取控制是通过用户登录口令来控制的,因此,文件的保护、保密,关键在于用户口令的选取和保护。Linux系统中,文件的存取权限可以通过特定的用户命令来修改,具体的控制方法,参看本书第3部分相关内容。 实际上,计算机硬件故障、系统软件缺陷,都会影响到文件的安全性,都可能涉及到文件的保护和保密问题,这些内容不属于本书的讨论范围。
  • 328. 6.3.3 Linux目录分布 Linux系统中采用的是树形的多级目录结构。 只有在没有使用链接文件的情况下,整个文件系统构成完整的目录树,每一个目录或者文件都有惟一的绝对路径来确定。如果为了达到共享目的,建立链接文件之后,目录树就由树状结构变成了网状结构,被共享的文件内容可以通过不同的绝对路径来访问,造成有些文件的绝对路径不惟一。
  • 329. 图6.9 Linux文件系统目录层次结构图
  • 330. Linux系统根目录下通常有多个默认的子目录,它们是bin实用程序子目录,存放大多数用户都可以使用的常用系统工具;boot子目录,存放系统启动时必须的内核映像等文件;dev设备子目录,系统在这个子目录里为每个设备分配一个i节点;etc基本数据子目录,存放系统的用户口令、网络配置等设置文件,home用户数据子目录,默认情况下,每个用户登录后的工作目录都设在这个目录下;lib系统函数库子目录,存放着系统提供的动态和静态库函数;proc系统状态子目录,通过这个目录,可以动态地了解系统内核的运行情况;root系统管理员的用户目录;sbin系统管理实用程序子目录;另外还有tmp临时文件目录、usr用户软件子目录以及var记载系统运行情况的日志子目录。
  • 331. 除了这些默认的子目录之外,系统管理员还可以根据实际需要在根目录下建立新的子目录,比如专门用来安装(mount)其他文件系统的特殊子目录等等。一般用户,通常只能在自己的工作目录下或者其他得到授权的目录下工作,根据需要建立合适的子目录,安排自己的文件,未经授权,一般用户无法访问其他人的用户目录及其中的文件。
  • 332. 6.3.4 Linux目录文件 Linux系统中,目录也是文件的一种,称为目录文件,每一个目录也由一个i节点来描述,i节点中文件类型标识这是一个目录文件,同时在对应的物理块中存放用来描述文件的目录项列表。 目录项列表用来描述一个目录所包含的全部文件和子目录,每一个目录项对应着一个文件或目录,具体的数据结构为:
  • 333. struct ext2-dir-entry-2 { —u32 inode; /* Inode number */ —u16 rec-len; /* Directory entry length */ —u8 name-len; /* Name length */ —u8 file-type; /* File type*/ char name\[EXT2-NAME-LEN\]; /* File name */ }; 每一个目录项中记录着该文件的名称和对应的i节点 号等信息。任何一个目录表的前两项内容都是标准 目录项“.”和“..”。
  • 334. 当用户给出一个完整的路径名,比如/home/dy/linux/kernel/sched.c,首先得到文件系统根目录对应的i节点,读取其中的信息,根据文件类型判定是一个目录文件,在这个i节点保存的目录项列表中找到名称为home的那一项,查找该目录项就可以得到这个子目录对应的i节点,然后再读取该i节点的信息,每一个目录文件中都保存着自己所包含文件和直接子目录的目录项,逐个查找,最终可以找到所需要文件的i节点号,访问相应的i节点,通过该i节点的索引表,得到存储文件内容的物理块,就得到了指定文件的内容。整个访问过程中多次访问不同的i节点,系统是通过在内存中建立一张内存i节点表来实现的,查找i节点可以直接在内存中进行,这样就提高了文件的访问效率。
  • 335. 6.3.5 特殊目录 在系统默认的目录中,最值得注意的是dev设备子目录和proc系统进程子目录。 1. /dev子目录 系统所有的设备文件都存放在dev设备子目录下。每一个设备文件也使用惟一的i节点来标识,设备文件i节点不指向文件系统中的任何实际的物理块,不占用数据空间,通过这个i节点可以访问相应的设备驱动,对设备文件的操作就是直接对设备本身进行相应的操作。Linux系统中有两种类型的设备文件:字符设备文件和块设备文件,分别对应于系统的字符设备和块设备。
  • 336. 每一个设备文件的文件名由该设备的名称以及它的从设备号来描述。例如在系统中第一个IDE控制器上的主硬盘的设备名称号为hda,它上面的第一个分区的从设备号为1,所以这个分区对应的文件名就是/dev/hda1。使用命令ls -l /dev/hda*就可以看到第一个硬盘可能包含的全部设备文件: brw-rw----1 root disk 3, 0 May61998 hda brw-rw----1 root disk 3, 1 May61998 hda1 brw-rw----1 root disk 3,10 May61998 hda10 brw-rw----1 root disk 3,11 May61998 hda11 brw-rw----1 root disk 3,12 May61998 hda12 brw-rw----1 root disk 3,13 May61998 hda13 brw-rw----1 root disk 3,14 May61998 hda14 brw-rw----1 root disk 3,15 May61998 hda15
  • 337. brw-rw----1 root disk 3,16 May61998 hda16 brw-rw----1 root disk 3, 2 May61998 hda2 brw-rw----1 root disk 3, 3 May61998 hda3 brw-rw----1 root disk 3, 4 May61998 hda4 brw-rw----1 root disk 3, 5 May61998 hda5 brw-rw----1 root disk 3, 6 May61998 hda6 brw-rw----1 root disk 3, 7 May61998 hda7 brw-rw----1 root disk 3, 8 May61998 hda8 brw-rw----1 root disk 3, 9 May61998 hda9 其中第一个字符都是b,表明是块设备文件,接下来的9位数字控制设备文件的访问权限,表示只有设备所有者root和所属disk组成员可以读写,所有设备的主设备号都是3,从设备号依次为0到16,最后给出的是设备文件名。
  • 338. 2. /proc子目录 在proc子目录下存放的是关于当前运行系统的动态资料。这个目录及其所包含的文件属于一个称为proc的逻辑文件系统,和其他文件系统不同的是,proc文件系统是一个并不真正存在于块设备上的文件系统,这个目录下的文件也并没有存放在设备中。在系统的初始化过程中,proc 文件系统注册并建立该目录下所有的i节点,而只有当访问到其中的目录或文件时,Linux虚拟文件系统才利用内核信息实时地建立这些文件和目录的内容。
  • 339. proc目录为用户提供了几乎全部系统运行的动态资料,CPU、内存、系统各种外部设备、中断等计算机硬件和设备控制信息,以及内存资源和外部设备的使用情况,系统中所有当前进程的工作情况等等。每一个当前存在于系统中的进程都在proc目录下有一个子目录,进程号是该目录的名称,如果用户希望了解1号进程的当前情况,使用命令ls -l /proc/1,就可以看到该进程的相关内容如下:
  • 340. total 0 -r--r--r-- 1 root root0 Nov2 23:25 cmdline lrwx------1 root root0 Nov2 23:25 cwd -> / -r-------- 1 root root0 Nov2 23:25 environ lrwx------1 root root0 Nov2 23:25 exe -> /sbin/init dr-x------2 root root0 Nov2 23:25 fd pr--r--r--1 root root0 Nov2 23:25 maps -rw-------1 root root0 Nov2 23:25 mem lrwx------1 root root0 Nov2 23:25 root -> / -r--r--r-- 1 root root0 Nov2 23:25 stat -r--r--r-- 1 root root0 Nov2 23:25 statm -r--r--r-- 1 root root0 Nov2 23:25 status
  • 341. 从上面的内容可以看到,这个进程对应的应用程序是/sbin/init,建立这些文件和目录的时间就是运行ls命令的当前时间,同时每一个文件的大小都是0,即没有使用任何磁盘空间。可以通过这个目录下的stat、statm和status文件进一步了解进程的执行状态,例如,我们可以使用命令cat /proc/1/status来显示init进程的当前情况: Name: init State: S (sleeping) Pid: 1 PPid: 0 Uid: 0 0 0 0 Gid: 0 0 0 0
  • 342. Groups: VmSize: 1120 kB VmLck: 0 kB VmRSS: 476 kB VmData: 36 kB VmStk: 8 kB VmExe: 24 kB VmLib: 1024 kB SigPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: ffffffffd7f0d8fc SigCgt: 00000000280b2603 CapInh: 00000000fffffeff CapPrm: 00000000ffffffff CapEff: 00000000fffffeff
  • 343. 进程的名称、进程号以及所处状态等基本信息,用户号、用户组号等信息,以及内存空间,信号状态等各种更为详细的资料都一览无余。 综上所述,proc目录可以看作是一个观察系统内核内部工作情况的途径和窗口,通过这个目录下的内容,用户可以动态地了解计算机的软、硬件运行情况,可以用于实时监测,进行系统故障诊断。
  • 344. 6.4 逻辑文件系统——Ext2 在整个Linux文件系统中,逻辑文件系统屏蔽了具体的设备细节,向虚拟文件系统提供服务,它真正存在于物理设备中。Linux系统可以支持几十种不同的文件系统,比如DOS系统的MSDOS文件系统、Windows NT的NTFS文件系统,MINIX系统的MINIX文件系统等等,它们都属于逻辑文件系统。Linux本身默认的逻辑文件系统是Ext2。 6.4.1 Ext2文件系统 Ext2文件系统是一种具有伸缩性,高效、可靠的逻辑文件系统。
  • 345. 1. Ext2文件系统的历史 Linux操作系统最初是从MINIX操作系统发展起来的,它最早使用的文件系统是MINIX文件系统,但是MINIX文件系统本身功能不完备,性能欠佳。 称为VFS的虚拟文件系统接口加入到系统的核心。1992年,专为Linux设计的第一个文件系统Ext(Extended File System)诞生了,碎片和效率是其中最为严重的两个弱点。 1993年,推出了新的专门用于Linux系统的Ext2 文件系统。Ext2 完全具备了高级文件系统的特点,性能也相当好,Ext2文件系统采用可变大小的物理块,具有良好的可扩展性,作为所有Linux发行版本的默认文件系统。
  • 346. 2. Ext2文件系统的布局 系统中的文件和目录等信息都存放在磁盘等块设备中,一个Linux系统可以支持多个物理磁盘设备,这主要取决于计算机硬件的支持能力,通常的PC中,最多可以支持到4或8个IDE设备,每一个物理磁盘又可以定义多个分区,每个分区是存放逻辑文件系统的最小单位。在Linux系统中,这些分区可以安装不同的逻辑文件系统,系统可以同时使用这些文件系统,而且在用户的眼里,它们表现出基本相同的性能,互相之间可以进行数据传输,这就是Linux虚拟文件系统的优势。
  • 347. 每一个逻辑文件系统都按照不同的规则,把自己所控制的磁盘分区定义为一组逻辑块的序列,通常包括引导块、超级块、i节点区和数据区。 引导块在磁盘分区的头部,一般占用一个扇区,用来存放引导程序。在系统启动过程中,根据系统引导设置,该分区引导块的内容被读入内存执行,负责启动操作系统,启动完成之后,引导块不再使用,因此引导块在系统实际运行过程中并不属于文件系统管理。 超级块用来记录整个逻辑文件系统的基本管理信息,不同的文件系统中定义为不同的数据结构,主要用来记录文件系统当前的状态,比如文件系统的大小、i节点和物理块的使用情况等等。
  • 348. i节点区存放这个逻辑文件系统中所有的i节点,第一个i节点是这个系统的根节点,其他所有文件和目录都占用一个i节点。利用根节点,可以把存放在这个磁盘分区的整个文件系统安装到另一个文件系统的枝节点上,作为另外文件系统完整的一棵独立子树。 数据区中存放文件系统中的各种物理块,可以存放直接块和各种间接块等文件内容,也可以用来存放各级间接块的地址等管理数据。 Ext2文件系统把它所占用的磁盘分区首先分为引导区和块组,每一个块组中都由超级块、记录所有块组信息的组描述符表、块位图、i节点位图、i节点区和数据区组成,见图6.10。
  • 349. 图6.10 磁盘分区中Ext2文件系统的布局
  • 350. 每个块组中的超级块和组描述符都是相同的,前者记录整个文件系统的管理信息,后者记录每个块组的描述符。在系统启动的过程中,只有第一个块组中的超级块和组描述符被读取到内存空间中,其他块组中的数据作为冗余备份。此外,所有块组中的超级块和组描述符必须保持一致,当系统意外关机遭到部分破坏后,系统启动之后要进行文件系统一致性检查,首先要检查的就是这些数据,冗余数据虽然占用了一部分存储空间,但是提高了文件系统的可靠性。 Ext2系统采用位图来描述空闲物理块和i节点,分别称为块位图和i节点位图,记录本块组数据区中物理块和i节点区中i节点的使用情况。
  • 351. 6.4.2 基本数据结构 本节介绍Ext2文件系统主要数据结构。超级块和i节点是其中最关键的两个结构,i节点用来描述各种类型的文件,是整个文件系统的基本管理单元,超级块则是描述整个文件系统的重要数据,是这里要介绍的重点。另外,这里还介绍组描述符。它是描述文件系统块组分布和使用情况的主要数据。 1. 超级块 Ext2文件系统的超级块用来描述目录和文件在物理设备上的静态分布情况,随着系统文件操作,超级块的内容也在不停地改变。对于PC机来讲,每一个磁盘分区都格式化为一个独立的文件系统,具有自己的超级块。
  • 352. 超级块包含物理块和i节点的分配情况以及文件系统安装、检查情况等基本参数,描述整个文件系统的分布情况,同时也用于空闲i节点和物理块的分配和回收,是文件系统中最重要的数据,如果超级块的数据被破坏而且无法恢复的话,这个文件系统所管理的磁盘分区的数据就有可能全部丢失,因此超级块被同时记录在整个文件系统的每一个块组中,尽可能保证它的安全。系统根据超级块中的检查信息,确定整个文件系统的状态,如果发现错误或者是文件系统使用超过一定时间之后,都需要对整个文件系统进行检查,修正错误,整理磁盘碎片。
  • 353. 根据所存放的位置,超级块也可以分为磁盘超级块和内存超级块,分别用结构ext2-super-block和ext2-sb-info来描述。其中磁盘超级块静态存放在外部存储器,而内存超级块是在文件系统启动时由外部超级块初始化形成,除了包含外部超级块所记录的信息之外,还增加了描述文件系统当前状态的动态信息和指向文件系统缓冲区的指针。内存超级块是系统内核其他部分进行文件操作的接口,内存超级块在文件操作发生之后通常会被修改,系统定期用内存超级块的数据更新磁盘超级块的内容。
  • 354. 2. 组描述符 块组是Ext2文件系统划分和管理文件系统的单位,每个块组都由一个组描述符(group descriptor)来具体描述,组描述符定义为ext2-group-desc数据结构,主要记录了该块组中空闲物理块和i节点的数目和描述它们的位图表的位置等信息,通过它可以管理整个块组内存储空间的分配和回收,它在块组中的地位就相当于超级块在整个文件系统中的地位。 整个文件系统的所有块组的描述符集中在一起,形成组描述符表,这张表在每一个块组中都保存一个相同的副本,以便得到有效的保护。组描述符表位于该块组中超级块之后,可能占用多个数据块。
  • 355. 6.4.3 存储空间管理 文件系统的主要目标除了实现文件的有效管理和使用,同时还要保证存储器资源的有效利用。Linux系统默认的Ext2文件系统采用分块的组织方式,利用多重索引的物理文件结构来实现外部存储空间的管理。 1. 块的大小 Ext2逻辑文件系统中,块的大小可以在一定范围内调整,但是在格式化磁盘分区生成文件系统时必须指定块的大小,因此每一个实际存在的Ext2文件系统的块的大小都是固定的,块的大小对文件系统性能和存储空间利用率有相当大的影响。
  • 356. 如果块这个存储管理的基本单位选取比较大的话,存储空间的利用率就可能比较低。反过来,如果存储单元选取很小,文件系统的时间效率就很低。因此,时间效率和空间利用率是一对矛盾。一般, 文件系统块的大小可选值为512、1K、2K或者是4K字节,Ext2文件系统数据块大小的可选值是1K~4K字节。 通常块的大小根据文件系统中文件的平均长度来选取比较合适。前面我们学习过,Linux使用的Ext2系统中采用多重索引方式来组织文件,块大小选取的标准是:能够保证大部分文件都可以用12个直接块存放,这样,每次寻址只要访问i节点就可以得到物理块的地址,能够保证相当高的时间效率。
  • 357. 2. 空闲空间管理 系统对所有使用和未使用的存储空间,在Ext2文件系统中包括i节点和物理块,都需要做精确的记录,这是内存进一步分配和回收的依据。块的使用情况,具体记录在每一个文件的i节点中,而i节点的使用情况,记录在目录项中,这些都可以通过文件系统实现快速搜索和管理。 文件系统记录空闲存储空间,包括记录空闲块和空闲i节点,广泛采用的两种基本方式是空闲链表和位图,同样的方法也可以用来管理空闲内存。
  • 358. 我们以空闲块的管理为例简单说明这两种方法的基本原理。空闲链表把文件存储设备上的所有空闲块装入一个链表中,每一个空闲块中都记录着下一个空闲块的地址指针,通常以多个相邻空闲块组成的空闲区作为链表的节点单元,分配和释放空闲块也尽可能以空闲区为单位,可以按照空闲区大小顺序或者释放顺序来组织链表。当申请使用硬盘空间时,从链表头开始搜索并分配合适的空闲区,然后相应地调整链表指针,当回收空闲块时,把释放的存储空间按照空闲区为单位加入到链表中。
  • 359. 位图方法是在存储区中划分一个单独的区域建立位图,位图中的每一个比特位数据都对应于存储区中的一个块,使用“0”来表示空闲,使用“1”来表示已经使用(或者相反)。这样,位图就可以反映整个存储区域中所有块的使用情况。分配和释放的过程中,只要通过查找位图中相应位的数据,就可以确定指定块的使用情况。 空闲链表具有较好的空间效率,但是时间效率比较低。而位图方法需要占用固定的存储空间,但是具有很好的时间效率。
  • 360. Ext2文件系统的空闲空间管理采用位图方式,在每个块组中都划分了特定的位图区来记录块和i节点的使用情况,分别称为块位图和i节点位图,参看图6.10。每一种位图分别占用一个块的空间,如果某一位的值为“0”,表示相应的块或者i节点空闲,反之则表示已经分配。Ext2文件系统采用两个高速缓冲区来分别管理这两种位图,以提高时间效率。 3. 分配策略 当建立一个新的文件或者目录时,文件系统必须决定使用哪一个i节点来表示它,同时还要分配相应数目的块来存放数据。当一个文件在操作过程中,添加了新的内容,文件系统也必须确定给这个文件加入新的块来存放这些内容。
  • 361. i节点和块的分配策略在一定程度上决定着文件系统的整体效率。Ext2文件系统采用块组的概念,尽可能把同一个文件所使用的块、同一个目录所使用的i节点存放在相邻的单元中,至少是在同一个块组内,减少磁盘访问过程中的寻道时间,以提高访问效率。具体对于一个新分配的i节点,新目录尽可能保证它和父目录分配在同一个组当中,新文件也要尽可能保证和目录同组,同时,尽可能保证所有的节点平均分配到所有的块组中。
  • 362. Ext2文件系统采用称为预分配的机制来保证文件内容扩展时块的分配效率和效果,在文件建立的时候,如果有足够的空闲块,就在相邻的位置为文件分配多于当前使用的块,称为预分配块,当文件内容扩展时,优先使用这些块,可以提高分配效率也可以保证这些块具有连续关系。如果预分配的块用完或者是根本没有启动预分配机制,分配新块时也要尽可能保证与原有块相邻。 在申请分配i节点和空闲块的过程中,都需要改写文件系统的超级块,在分配过程中,必须要申请使用超级块并加锁,超级块分配采用的是先来先服务算法,后面申请的进程必须等待,直到所有前面申请的进程都使用完解锁并释放才可以得到超级块的使用权。
  • 363. 6.5 虚拟文件系统——VFS Linux虚拟文件系统位于Linux整个文件系统的最上层,提供文件系统对用户命令、系统调用及内核其他模块的统一接口,它负责管理并控制下层的逻辑文件系统,使它们按照各自特定的模式正常运转,同时能够对用户提供尽可能相同的表现形式。 虚拟文件系统只存在于内存中,并没有真正存在于磁盘分区中,磁盘分区存放的是逻辑文件系统的内容,所有虚拟文件系统的数据结构都是在系统启动之后才建立完成,并在系统关闭时撤销。同时,它必须和其他实际存在于磁盘的文件系统,比如Linux默认的Ext2或者Windows NT的NTFS等逻辑文件系统一起,才能构成一个完整的文件系统。
  • 364. 虚拟文件系统对逻辑文件系统进行抽象,采用统一的数据结构在内存中描述所有这些文件系统,接受用户层的系统调用和核心层其他模块的访问,通过VFS操作函数,按照一定的映射关系,把这些访问重新定向到逻辑文件系统中相应的函数调用,然后由逻辑文件系统来完成真正的具体操作,这样,VFS只负责处理设备无关的操作,主要是进行具体操作的映射关系。正是VFS的这种抽象的功能层次,保证了Linux系统可以支持多种不同的逻辑文件系统,所有文件系统都具有基本相同的外部表现,而且可以方便地进行相互访问。
  • 365. 针对下层的逻辑文件系统,Linux系统中的VFS为它们提供一致接口,统一管理各种逻辑文件系统,包括进行文件系统的注册和注销、安装和卸载等,提供限额机制,负责对用户使用存储空间的数量进行有效控制。把文件操作进行适当的转换,转交由具体逻辑文件系统进行处理,然后把具体的操作结果提供给上层的调用者。针对上层,VFS对用户函数调用和内核其他模块的访问提供接口,接受访问并返回由具体逻辑文件系统完成的结果。此外,VFS还负责管理文件系统的各种缓冲区,保证文件系统的整体效率。
  • 366. 6.5.1 基本数据结构 VFS采用超级块和i节点来描述文件系统,这些基本的数据结构在文件系统初始化的过程中,由具体逻辑文件系统的超级块和i节点的数据来填充,而当文件系统关闭时,VFS的超级块和i节点也就消失了。 1. VFS 超级块 初始化完成之后,对于每一个可以访问的逻辑文件系统,都对应于一个VFS超级块,这些数据驻留在系统内存。VFS文件系统的超级块用来描述初始化它的具体逻辑文件系统的目录和文件在物理设备上的静态分布情况,随着逻辑系统文件的改变,VFS超级块的内容也在变化。
  • 367. VFS超级块使用数据结构super-block来描述。在VFS超级块中,记录具体逻辑文件系统所在的设备号、类型、第一个i节点号等基本信息,包含了对该文件系统文件操作和存储空间限额管理函数的入口指针和所对应的具体逻辑文件系统的内存超级块。虚拟文件系统就是通过VFS超级块中记录的内存超级块来访问并管理具体的逻辑文件系统的,文件操作通过VFS中记录的函数入口指针映射得到对应的函数。图6.11以Ext2文件系统为例描述了逻辑文件系统磁盘、内存超级块和VFS超级块之间的关系。
  • 368. 图6.11 Ext2磁盘超级块、内存超级块和VFS超级块 关系示意图
  • 369. 整个Linux文件系统形成一个完整的目录树,每一个逻辑文件系统都可以作为一个独立的子树安装到目录树的某个枝节点上。因此,VFS超级块中采用指针s-covered记录着该文件系统在另外一个文件系统中安装点的信息,同时VFS超级块中还使用指针s-mounted记录指向该逻辑文件系统的第一个节点的位置。对于根文件系统,s-mounted就是根目录的i节点,它没有安装到其他文件系统,s-covered指针无效。对于安装在根文件系统下的文件系统,访问该文件系统管理的文件首先要通过根文件系统,根文件系统中的安装点指针s-covered就是该文件系统的访问入口,指向该文件系统的根节点。
  • 370. 2. VFS i节点 VFS i节点用来描述虚拟文件系统中的文件和目录,同样的,每一个文件、目录或者设备都对应于一个且只能对应于一个i节点。VFS i节点只存在于内存中,是所有逻辑文件系统i节点的抽象描述,和具体逻辑文件系统的i节点一一对应,并根据该文件系统的i节点信息建立。
  • 371. VFS i节点包含具体i节点所在设备的设备号和磁盘i节点号、文件说明信息、文件在内存中的分布和使用信息、锁定和修改标志、一组VFS i节点操作函数指针和一个具体逻辑文件系统内存i节点。设备号和磁盘i节点号在整个文件系统中惟一确定一个VFS i节点。在内存中,总是同时存在多个VFS i节点,每一个已经使用的VFS i节点表示某设备上一个具体存在的文件或者目录的i节点,所有VFS i节点组织成一个双向链表,存放在系统内核空间中,链表的头节点之前存放空闲节点,而链表头之后依次是分配出去的VFS i节点。
  • 372. 在用户或者内核看来,对目录和文件的操作是对VFS i节点进行的。实际上,VFS i节点根据逻辑文件系统的类型,利用存放在其中的节点操作函数指针,对操作函数进行相应的映射,得到具体逻辑文件系统i节点操作函数,对具体的i节点进行操作,把结果返回给使用者。
  • 373. 6.5.2 文件系统管理 Linux系统利用虚拟文件系统VFS实现对多种文件系统的有效支持,虚拟文件系统负责管理具体的逻辑文件系统,同时也可提供用户存储空间限额管理。 1. 逻辑文件系统管理 某种类型的逻辑文件系统要得到Linux操作系统的支持,首先必须向核心注册。可以采用两种方式,一种是在内核编译过程中确定要支持的文件系统类型,并在系统初始化过程中使用特定的函数调用注册,另外一种方式是在系统启动完成之后,把某种逻辑文件系统类型作为一个内核模块加入到内核中,加入模块时完成注册。
  • 374. 每一个注册过的文件系统类型都初始化一个称为file-system-type的数据结构,所有这些数据结构组成一个单向链表,称为文件系统类型注册表。对于某一种文件系统类型,可以管理多个磁盘分区,也就是说有多个该类型的文件系统,但是它只占用类型注册表中的一个节点。当某一种类型的文件系统都不再使用时,可以使用卸载模块的方式来注销该文件系统类型。 对于一个具体的文件系统,在微机中就是每一个磁盘分区,要使用该文件系统所管理的文件,必须向内核注册和安装该文件系统,而当卸载一个文件系统时,还需要向内核申请注销该文件系统。
  • 375. 系统中所有注册的文件系统组成一个文件系统注册表,也采用一个单向链表来描述,节点类型为vfsmount,记录着对应文件系统的设备号、安装目录名称、超级块以及存储空间限额管理数据,文件注册表实际上可以描述整个目录树在文件系统层次上的构成情况(不能反映每一个文件系统中具体的目录分布)。图6.12示意性地描述了文件系统类型注册表、文件系统注册表和VFS超级块之间的关系。
  • 376. 图6.12 文件系统注册表、VFS超级块和文件类型 注册表关系示意图
  • 377. 文件系统类型注册表记录着整个系统当前所支持的全部文件系统类型,而文件系统注册表记录着整个系统中当前可以使用的全部文件系统,是操作系统访问具体存储设备上文件系统的入口。 看这样一个例子,一台微机只使用一块硬盘,同时安装了Linux和Windows 2000两个操作系统,分别使用不同的分区,不同的文件系统。假定Linux系统安装在第一个基本分区中,设备名称为/dev/hda1,采用默认的Ext2文件系统,Windows 2000安装在第二个基本分区中,设备名称为/dev/hda2,采用NTFS文件系统,基本分区/dev/hda3中是Linux系统的交换区,磁盘的逻辑分区/dev/had5是Linux系统的用户数据区,文件系统类型也是Ext2。
  • 378. 这种情况下,系统中同时存在Ext2、NTFS和Swap等三种类型的逻辑文件系统,要想同时支持这些不同类型的文件系统,必须首先注册这三种文件系统类型,在文件系统类型注册表中加入相应的节点,经过这一步,Linux系统的核心才能够支持相应的文件系统类型。在这个例子中,如果要使用所有的磁盘分区,还必须把hda1、hda2、hda3和hda5所对应的具体文件系统都加入到文件系统注册表中。 在Linux系统启动的过程中,根据记录在/etc目录下的fstab文件确定并安装文件系统,形成初始目录树。在启动完成之后,具有足够权限的用户,一般是超级用户,可以通过mount命令来安装特定的文件系统。
  • 379. 在安装过程中,需要明确指出所安装文件系统的类型、文件系统所在的设备号以及在已有文件系统中的安装点。安装过程中,首先在文件系统类型注册表中查找所指定的文件系统类型是否已经注册,如果没有注册,试图通过内核申请注册该文件系统,注册不成功则错误返回。一旦确定在文件系统类型注册表中有该文件系统,接着开始检查文件系统注册表,确定指定的文件系统是否已经安装,同样一个文件系统是不能多次安装的。确定该文件系统没有安装之后,检查安装点的合法性,每一个安装点也只能安装一个文件系统。
  • 380. 经过这三步检查之后,VFS分配新的超级块,利用文件系统类型注册表中对应的超级块读入函数,读取指定设备上文件系统的磁盘超级块并初始化这个VFS超级块,填写相应的s-covered和s-mounted信息。然后形成一个类型为vfsmount的节点,填写内容并挂到文件系统注册表链表中。
  • 381. 文件系统的安装过程,从用户的角度来看,就是把这个文件系统所记录的独立子树安装到已经存在的目录树某个枝节点上的过程。安装点指明枝节点的位置,它所对应的VFS i节点记录在VFS超级块的指针s-covered中,文件系统所在的设备号指出了独立子树的位置,这个文件系统中第1节点的位置所对应的VFS i节点号记录在VFS超级块指针s-mounted中。安装完成以后,所有对所安装逻辑文件系统的访问都是从文件系统注册表开始,通过VFS超级块得到具体文件系统的类型和位置(由VFS i节点号表示)以及操作函数映射到相应的逻辑文件系统,实现具体的文件操作。
  • 382. 通常Linux系统关机时会检测并卸载和注销所有已经安装的文件系统。一般运行过程中,只有在文件系统中的任何一个文件或者目录都没有被使用的情况下,超级用户可以使用系统命令umount来卸载并注销一个文件系统。VFS首先处理该文件系统对应的VFS超级块,如果需要,把它重新写入磁盘超级块中,然后释放该超级块,卸载完成,该文件系统对应的独立目录子树就从整个目录树中摘下来,最后释放文件系统注册表中相应的vfsmount节点,注销文件系统。
  • 383. 2. 存储空间限额管理 存储空间限额管理是多用户操作系统中所必须考虑的问题,利用这个技术,可以有效控制系统中每一个用户最多可以使用的存储空间,保证所有用户都有可用的空间资源。 限额管理可以分为软限额和硬限额两种。硬限额指定的存储空间范围绝对不可以超过,而软限额在用户使用资源超过限额范围之后,系统开始启动定时机制,如果在规定的限制时间之内没有采取措施缩减使用空间的话,软限额变成硬限额,强迫用户进程终止,释放所占用的资源。软限额到硬限额之间的时间可以由系统管理员来设置,系统默认值为一周。
  • 384. 限额分配情况是由限额文件来控制的,文件中以用户号为索引记录每个用户的空间限额配置资料,每一条记录称为一个限额块。每一个文件系统都有限额文件,存放在该文件系统的根目录下,在注册文件系统时,指向该文件的指针保存在文件系统注册表中。VFS超级块中保存着一个指向相应的限额处理函数的指针,每一个用户的限额块分别使用指针记录在该用户使用的每一个VFS i节点中。 当用户申请新的块或者i节点时,系统按照文件拥有者的用户标识号查找相应的限额记录,如果限额没有满,则接受申请,分配空间并加入到使用计数中,如果达到限额,调用相应的限额处理函数来处理,给出警告信息或者是进行硬限额处理。
  • 385. 6.5.3 VFS和进程的接口 前面介绍的是VFS针对下层逻辑文件系统的管理功能,作为一个独立的层次,它同时还向用户函数调用和内核其他部分提供服务,它对用户的服务,必须通过内核中的进程实体完成。这里,主要学习VFS文件系统和进程的各种接口。逻辑文件系统是程序和数据的静态组织,而进程反映这些程序和数据的动态过程,文件只有通过进程才能得到执行和访问,VFS的这些接口提供了它们之间联系的桥梁。
  • 386. 进程和文件系统的接口可以用图6.13示意性描述。进程中包括两个关于文件方面的数据,一个记录文件系统信息,另外一个描述进程打开文件的信息。前者是一个指向fs-struct结构的指针,主要数据是文件系统根目录和当前目录所对应的i节点号。后者是一个指向file-struct结构的指针,包含用户打开文件表,是该进程对全部已打开文件进行具体访问的接口。
  • 387. 图6.13 进程和用户打开文件表、系统打开文件表等数据结构的关系
  • 388. 1. 用户打开文件表和系统打开文件表 所有用户对文件的操作,不管是命令方式还是系统调用,最终都是通过特定的进程来实现。在Linux标识进程的PCB中,包含了用户打开文件表,用来建立该进程和所有该进程打开文件之间的联系,同时,系统中所有打开的文件也记录在一张称为系统打开文件表的双向链表中。
  • 389. 用户打开文件表记录是一个数组,记录在file-struct结构中,每一个进程中含有一个指向该表的指针,其中使用一个数组来存放所有该进程已经同时打开的文件,默认的数组大小为256,数组每一个元素fd\[i\]指向对应于一个file结构类型的指针,指向一个特定的文件,数组元素的下标称为文件描述符,供用户操作文件时使用,每次成功打开一个文件,返回的结果就是这个描述符。每一个进程在建立的时候,用户打开文件表中都有默认的三个打开文件,其描述符分别为0、1和2,分别对应于系统标准输入设备、系统标准输出设备和系统标准错误输出设备。每当用户进程打开一个新文件,系统就在fd数组中选定其中第一个空闲的元素来指向对应的file结构,代表特定的文件。
  • 390. 系统打开文件表描述系统已经打开的文件,具体指明打开同一文件的不同进程、不同进程所对应的打开路径以及不同进程和不同打开路径所对应的读写位置指针。每一个打开文件使用一个file结构描述,包括文件打开方式、读写位置指针、文件访问计数、文件VFS i节点指针和文件操作指针等关于文件的具体数据以及前后向指针。
  • 391. 进程通过控制块PCB得到文件系统信息和对应的用户打开文件表,该表的每一个表项指向一个已经打开的文件,这些打开文件统一由系统打开文件表来管理,打开文件中记录该文件当前打开方式、读写指针等基本信息和文件对应的i节点信息以及操作函数,有了这些信息,进程就可以进行具体的文件操作。
  • 392. 2. 共享文件访问 多个用户使用同一个文件称为文件共享,前面介绍的是文件系统中用户级别的文件共享方法和权限控制等问题,这只是问题的静态方面。具体共享文件的访问是通过不同的用户进程来具体操作的,这些进程可以属于不同的用户,也可以是同一个用户的不同进程,而且完全有可能两个进程同时对某一个文件进行操作,这里介绍具体的实现方法。
  • 393. Linux进程可以通过两种途径来实现文件共享。一种是多个进程同时共享使用一个系统打开文件表的节点(即file结构),该节点惟一对应于一个打开的文件,这种情况只在父子进程之间发生,一个新建立的子进程,复制父进程PCB中关于文件信息的全部内容,因此两者拥有完全相同的用户打开文件表,使用位于系统打开文件表中相同的节点。另外一种途径是多个进程使用多个系统打开文件表的节点,它们指向相同的i节点,这个i节点惟一确定一个文件,属于不同或者相同用户的进程同时访问一个文件就使用这种途径,不同进程打开同一个文件可以使用相同的路径名,也可以通过链接方式使用不同的路径名。
  • 394. 这里值得注意的是文件读写位置指针的情况,使用file结构共享文件的父子进程使用相同的文件读写位置指针,因此不管是父进程还是子进程在进行文件操作时都会改变指针的值。而指向相同i节点的共享方式,每一个进程都要进行文件打开操作,各自维护自己的file结构,分别使用不同的文件读写位置指针指向自己操作的当前位置。
  • 395. 6.5.4 缓冲区管理 在计算机系统中,内存的访问速度很快,因此,必须采用缓冲技术来提高外存数据的访问效率。缓冲技术的基本原理是在内存中划分称为缓冲区的特定区域,每次从外部设备读取的数据都暂时存放在这里,下次读取数据时,首先搜索缓冲区,如果有需要的数据,则直接从这里读取,如果缓冲区中没有,再启动外部设备读取相应的数据。对于写入磁盘的数据,也先放入到缓冲区中,按照一定的时间间隔或者数据量的大小,分批写出到磁盘中。这样,使用缓冲技术使得大多数数据传输都是直接在内存进程空间和缓冲区之间进行,减少外部设备的访问次数,提高系统的整体性能。
  • 396. VFS文件系统相关的缓冲主要有i节点缓冲、目录缓冲和块高速缓冲,分别用于i节点访问、根据文件目录名查找目录的i节点以及块设备的数据读写过程中的缓冲。 这里主要以Linux 2.2.16中块高速缓冲为例介绍缓冲管理的一般原理及其对系统性能的影响。 1. 块高速缓冲区结构 块高速缓冲(buffer cache)是文件系统和设备进行数据传输的桥梁,它同时涉及到不同的物理设备和逻辑文件系统,是各种设备驱动程序数据传输的接口,因此是一个相对复杂的数据结构。
  • 397. 每一个可以使用的缓冲区由两个部分组成,用于存放数据的缓冲数据区buffer和用于控制的缓冲头部buffer-head。为了支持各种不同类型的逻辑文件系统,Linux系统缓冲数据区的大小不是固定的,按照不同的长度分为7种类型。在同一时刻,缓冲区中可能包含不同物理设备的数据块,为了适应不同逻辑文件系统的各种不同大小的数据块,系统中同时采用多种不同大小的缓冲区。缓冲区头部大致包括三类信息:所在设备号、物理块号等描述缓冲区对应数据块内容的信息;描述缓冲区状态和访问计数的信息以及用于缓冲区管理的信息。对于缓冲区的分配、搜索、使用和释放等操作都是通过缓冲头部进行。
  • 398. 缓冲区状态是缓冲区最主要的信息之一。缓冲区状态可以是下面几种情况的组合:缓冲区是否包含有效数据,是否包含需要写出的数据,是否上锁,是否保护等等。 在Linux的块高速缓冲中,缓冲数据区和缓冲头部并不是完全一一对应的,整个块高速缓冲区中有四类以缓冲头部为节点的链表,其中两类不包含数据区,并不能进行实际的数据缓冲,主要涉及缓冲头部的管理,包括未使用链表unused-list和重用链表reuse-list,都采用单向链表存放;另外两类是真正的缓冲区,每一个链表的节点都是由一一对应的缓冲头部和缓冲数据区组成,分别是空闲链表free-list和正在使用链表lru-list,都使用双向链表来保存。
  • 399. 空闲链表free-list中保存由内存页面初次创建的缓冲区和从正在使用链表中回收的空闲缓冲区。系统中一共有7个这样的链表,分别对应于不同长度的缓冲区类型,它们共同组成一个链表数组。 正在使用链表lru-list存放当前正在使用的缓冲区,这是一个由3条链表组成的数组,分别连接不同类型的缓冲区: BUF-CLEAN,数据已经写出、干净的缓冲区; BUF-LOCKED,正在进行写出操作的缓冲区; BUF-DIRTY,“脏”缓冲区。写入新数据,等待写出的缓冲区。
  • 400. 为了提高查找效率,Linux同时还使用一个散列表(hash table)来组织所有的正在使用链表,如图6.14。表的节点类型是缓冲头部buffer-head类型,散列索引值通过缓冲区所对应物理块所在设备号及其块号来产生,具有相同索引数值的正在使用链表的节点组成新的双向链表。
  • 401. 图6.14 散列表和缓冲区链表的关系
  • 402. 2. 块高速缓冲区的分配和释放 当文件系统对某个数据块进行操作时,一定要通过块高速缓冲区来进行,必须分配相应的缓冲区,完成这个工作的函数是getblk。首先根据块对应的设备号和块号在散列表中搜索正在使用的链表中是否包含这个数据块,如果包含,就得到了需要的缓冲区,可以进行数据操作,否则,就需要重新分配一个空闲缓冲区。 分配空闲缓冲区时,根据所操作数据块的大小在相应的空闲缓冲区链表中查找,如果找到一个合适的空闲缓冲区,从空闲链表中摘下来该缓冲区,并初始化该缓冲区的控制数据,然后挂到相应的散列表和干净缓冲区链表中,得到可以使用的缓冲区。
  • 403. 如果空闲缓冲区中没有合适的缓冲区,系统就通过两种途径来补充空闲缓冲区的数量,一是申请空闲的内存页面,建立所需长度的新缓冲区并挂到相应的空闲链表中,二是唤醒进程bdflush把“脏”缓冲区写出到设备以得到空闲缓冲区,在完成这些操作的过程中,可能已经有别的进程曾经对这里需要访问的数据块进行过访问并在正在使用链表中建立了节点,因此再进行一次散列表的搜索,如果还是没有找到的话,就从空闲缓冲区中获取。内存空闲页面和缓冲区之间的转换关系参看图6.15。
  • 404. 图6.15 内存空闲页面和缓冲区之间的转换关系示意图
  • 405. 缓冲区的释放由函数tr-to-free-buffers完成。这个函数检查属于同一个物理页面的所有缓冲区,如果这些缓冲区都不忙(没有锁定、没有保护、干净),则可以释放这个页面对应的数据区,缓冲区头部则回收到未使用链表中。否则唤醒函数dbflush,试图把脏缓冲区写出到硬盘设备,然后再次判断是否可以释放。 3. 块高速缓冲区数据维护 Linux 需要采取适当的方式来维护块高速缓冲区,一方面保证不同块设备、不同的用户进程都能够公平地分配到缓冲区,同时还要尽快把数据写出到设备中,保证进程和设备数据的同步并适当减少缓冲区的内存使用量,以便能够使整个系统高效运行。
  • 406. 维护块高速缓冲区,把其中需要写出的“脏”缓冲区写到具体设备中是由两个内核线程bdflush和update来完成,它们直接使用系统空间,运行于内核态,具有较高的优先权。 内核线程bdflush的进程号为2,进程名称为kflushd。在以下几种情况下被唤醒:文件系统申请新缓冲区时,空闲缓冲区链表中为空,而且申请空闲内存页面建立新缓冲区没有成功,说明系统内存不足,需要减缩正在使用的缓冲区数量;系统正在使用缓冲区链表中的“脏”缓冲区超过一定的数目或者“脏”缓冲区数量已经占到块高速缓冲区总数的一定百分比以上,表明系统缓冲区中积累了大量需要写出的数据。bdflush负责将一定数量的“脏”缓冲区写出到具体设备,同时试图释放缓冲区所占的内存页面。
  • 407. 内核线程update的进程号为2,进程名称为kupdate。它周期性地被唤醒,按照“脏”缓冲区存在时间长短,把老的“脏”缓冲区写出到设备中,然后试图释放内存页面,它与bdflush的差别在于唤醒方式、确定要写出的缓冲区的标准不同,且它在写完之后,要改写缓冲区头部记录的时间标记,记录当前写出时间。 块高速缓冲区中的数据同时联系着设备以及用户进程,在使用过程中,用户进程对块设备的数据访问都通过缓冲区进行。采用的是异步写的方式。这样可以大大提高运行效率,但如果在数据进入缓冲区但是还没有写入设备之前系统崩溃,这些数据就丢失,造成文件系统数据错误,这也就是为什么Linux等操作系统不能直接关机的主要原因。
  • 408. 6.6 小结 本章介绍了Linux的文件系统。文件系统是用户接触、使用操作系统过程中面对的部分,它负责管理静态的文件。 文件是计算机存储信息的基本单位,Linux系统采用无格式的流文件,使用多重索引的方式以块为单位进行存储,利用目录组织成一个完整的目录树。Linux系统默认的逻辑文件系统是Ext2,其基本的数据结构是记录文件系统信息的超级块和表示文件和目录的i节点,使用块组技术,对文件系统中重要的数据(超级块和块组描述符)进行冗余备份,保证文件系统具有相当高的可靠性。
  • 409. Linux系统支持多种不同格式的文件系统,通过虚拟文件系统屏蔽了各种具体文件系统的差异,为用户命令、系统调用以及内核其他模块提供统一的操作接口,并负责把文件系统的操作映射到具体的逻辑文件系统和设备。Linux系统使用了块高速缓冲、目录缓冲以及i节点缓冲等多种缓冲技术,使得整个文件系统具有相当高的效率。 Linux系统提供了链接等实现文件和目录共享的手段,支持多个用户共同访问一个文件。也带来了相当大的安全性问题,具体包括保护和保密两种情况,这实际是一个文件的访问权限控制问题,Linux系统通过用户验证和简化的存取控制表来实现一定程度的共享安全性。
  • 410. 习题 6-1 什么是文件、文件系统?文件系统提供哪些功能? 6-2 什么是文件的逻辑结构和物理结构?Linux文件系统分别采用什么样的结构?有什么优点和缺点? 6-3 Linux文件可以根据什么分类?可以分为哪些类? 6-4 Linux采用什么样的目录结构?这种目录结构有什么优点?有什么缺点? 6-5 Linux文件共享可以用哪些方法来实现?它们各有什么特点? 6-6 Linux文件访问权限的控制采用什么方法?如何看待用户口令?你认为可以采用什么样的策略来保护口令本身?
  • 411. 6-7 通过文件系统如何了解Linux当前各进程的运行情况、内存占用情况? 6-8 在Linux系统中,Ext2磁盘i节点和内存i节点有什么不同?VFS有磁盘i节点和内存i节点的区别吗?为什么?这些i节点之间有什么关系? 6-9 在网上获取新的Linux核心,了解VFS超级块和i节点数据结构的变化情况。 6-10 Linux中和文件系统相关的缓冲区有哪些种?分别有什么作用? 6-11 bdflush进程有什么作用?什么情况下被唤醒?和它一样属于内核线程的还有哪些进程?
  • 412. 第2部分 操作系统命令及shell编程 第7章 Linux基本命令7.1 Linux的登录和退出 7.2 文件命令 7.3 目录和层次命令 7.4 查找命令 7.5 目录和文件安全性 7.6 磁盘存储命令 7.7 进程命令 7.8 联机帮助命令 7.9 小结 习题
  • 413. 本章介绍Linux基本的交互实用程序,包括登录和退出,文件命令,目录和层次命令, 查找命令,目录和文件安全性,磁盘存储命令,进程命令,联机帮助命令。没有列出的命令请通过联机帮助命令获取,通过这些实用程序的学习,使读者进一步理解Linux系统。
  • 414. 7.1 Linux的登录和退出 1. 启动Linux系统 启动Linux系统需要的过程可能和其他操作系统有点不同。 如果计算机没有安装其他操作系统,只需接通电源,等待数秒后将看到计算机显示LILO,然后系统再暂停一会,接着会继续显示各种启动信息。但是,如果让Linux和其他操作系统共享一台计算机,就必须执行以下任务: 在LILO提示下选择Linux(如果设置的名称是Linux)——如果安装了LILO, 并为包含其他操作系统的分区标注了启动标记, 计算机就被设置成多重引导。 这就意味着可以在LILO Boot:提示符下输入想引导的操作系统的名称。 如果在
  • 415. LILO 提示下按Tab键, 会看到LILO可以引导的操作系统的清单。 选择Linux, 就可以运行了。 使用传统的DOS操作系统时,只要打开电源,等待主机从软盘或硬盘启动即可,当出现“C>”时,表明系统已成功启动,可以在“C>”后运行各种命令了。但Linux系统却没这么简单。当从硬盘或软盘引导Linux时,将在系统控制台上打印大量信息,表明启动的整个过程。这些信息将分别存放在/var/log/syslog和/var/log/messages等文件中。这些信息对于事后分析系统的启动过程有着重要的作用。大量信息打印完,最后出现login提示符。
  • 416. 2. 登录Linux系统 我们对系统的使用都是从登录开始的。首先要求使用者必须拥有一个合法的个人账号,只有系统认可了的账号,才会获得系统的使用权。系统有两种用户:超级用户root和一般用户。当机器启动完毕后,将看到以下类似的信息: XLinux release 1.0 Kernel 2.2.12-4XL on an i686 login: 从最后一行可以看出, 现在可以登录了。
  • 417. 第一次登录Linux系统必须以超级用户root身份登录。这个账号对系统的一切拥有完全的控制权限。通常用root账号进行系统管理及维护,包括建立新的用户账号,启动、关闭、后备及恢复系统等。 因为root的权限不受限制,一旦误操作可能会导致不可预料的后果,所以在以root身份登录时, 必须格外小心, 并且只有在必须时才用root登录。如果是系统管理员或者独自拥有这台机器,就可以用超级用户登录。登录的方式是在系统提示符后键入root, 例如: login:root Password:
  • 418. 键入root账号后,按下回车键,然后在系统提示Password后输入超级用户的密码。系统将验证输入的用户名和密码是否正确,若正确,会出现如下提示: [root@ xLinux /root] # 这表明已经进入系统,此处的“#”符号是超级用户的系统提示符,而普通用户的提示符是“$”。如果密码输入错误,将出现如下提示: Login incorrect 稍后,又会出现“login:”,要求重新输入用户名。
  • 419. 注意,这里输入的密码并不在屏幕上回显,这样独特的设计同样是为了安全的需要,以免旁边的人轻易地看到密码。正像在Windows中输入密码使用 “*”显示一样,它有效地保护了密码,维护了系统的安全性。 普通用户登录时,过程相似。例如,有个用户zhang,登录如下: XLinux release 1.0g Kernel 2.2.12-4XL on an i686 login:zhang Password: 密码正确后将出现如下提示: [zhang@ xLinux zhang] $
  • 420. 一旦注册进入系统后, 可以用passwd命令来修改密码。 这时系统会询问当前的密码, 然后是新密码: [zhang@xLinux zhang]$ passwd Changing password for zhang (current) UNIX password: New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully [zhang@ xLinux zhang] $
  • 421. 与root不同的是,这里的提示符是“$”。提示符的不同只是系统对不同级别用户的一种标识,有时使用了不同shell程序的用户的提示符也不相同。 进入系统后,就可以执行各种任务了。 3. 退出Linux系统 当用户执行完各种操作后,就要及时退出系统,这是一个良好的习惯,即使是暂时离开机器也同样如此。退出的操作很简单,只需键入下面的命令即可: [zhang@ xLinux zhang] $exit 在提示符$后键入命令exit后回车即可退出系统,重新出现login提示符。有的系统中用logout,或按下Ctrl+d也能退出或注销用户,但我们推荐使用exit命令。
  • 422. 4. 重新启动和关闭系统 有时在对系统的某一配置做了修改以后,或者安装了新的软件,需要重新启动才能使所做的修改生效,这时就要用到重新启动命令reboot,它需要超级用户的权限。进入超级用户后,命令如下: [root@ xLinux /root] #reboot 键入reboot命令后回车,系统将重新启动。还有一种重新启动的方法是不需要先进入超级用户,在login状态下,同时按下Ctrl+Alt+Del键,系统同样可以重新启动,这就是所说的热启动。当做完所有的工作后,我们就要关闭系统了,这时切不可直接关掉电源,一定要首先执行关闭系统命令。此命令的执行同样要在超级用户下执行, 命令如下:
  • 423. [root@ xLinux /root] #halt 关闭系统命令是halt,有的系统可能是haltsys,不同的版本可能稍有差别,这可以参照不同版本的说明书。其实,一般的关闭系统命令是shutdown,它的具体用法将在以后详述。 5. 为什么使用关闭系统命令 如前所述,Linux在内存中缓冲了磁盘读写。通常,对磁盘同一个块的多次读写可能实际上是对RAM(Random Access Memory)的操作,这极大地提高了系统的性能,但是,如果出现意外情况,如突然掉电或者机器重启动,内存缓冲区中的数据将不能写进硬盘,造成数据丢失。所以,为防止这种无谓的损失,大多数系统都采取了补救措施,由
  • 424. /etc/rc.d/rc.s或rc.sysinit启动的/sbin/update程序每30秒钟把缓冲区的内容写入磁盘。这在一定程度上保证了数据的及时写盘。但为了安全起见,在系统结束运行前仍需有一个安全的关闭。这不仅能保证磁盘缓冲区正确地同步,而且可以让所有正在执行的进程正常地退出。
  • 425. 7.2 文件命令 在Linux系统中,几乎所有内容包括文档、命令、设备和目录等都组织成文件的形式,用文件来管理, 常用的文件命令有: 1. cat、more、less命令 (1) cat命令 功能:显示文本文件内容 语法: cat 文件名称 范例: $cat file1 显示file1的内容。
  • 426. $cat file1 file2 > file3 把file1和file2的内容输入到file3中。 (2) more命令 功能: 一次以一个page显示 语法: more 文件名称 描述:通常在看一篇很长的文件时都希望是从头 看到尾,在Linux中,more命令可以以一个page为单位来浏览文件。当使用more时,可看到屏幕的左下方有一个“--more--”的信息,这时若按下回车键,则会显示下一行;若按下空格键,则会显示下一个page。
  • 427. (3) less命令 功能: 与more命令相似,一次以一个page显示, 可以前翻、后翻 语法: less 文件名称 描述:若按下空格键,则会显示下一个page, 按下回车键则一行行地下翻,按下b键往上翻一页。 相关命令:zless 2. ls命令 命令名称: ls 功能: 查看目录及文件 语法: ls
  • 428. 描述:ls命令用来浏览文件与目录,这个动作相当于DOS中的dir命令。 例如:ls -l- -rwxr--r-1 root dba 65520 Jan 29 1998 profile1 -rw-r—r--1 root dba 103614 Jan 29 1999 services 这里大家看到的-rw—r--r是文件的许可权限,r是读权限,w是写权限,x是执行权限。 3. cp命令 命令名称 : cp 功能: 拷贝文件 语法:cp 文件 目的地
  • 429. 描述:其实cp的语法与DOS的copy语法大致相同。须注意的是,在使用cp时一定要有目的地才行,在DOS中做copy 时,有时可省略目的地,但在Linux中就无法这样做。在cp中也可以使用通配符,像“*”、“?”等,例如,我们要将root目录内的所有文件,但不包括隐藏文件,拷贝至根目录下的temp内,其命令为: #cp /root/* /temp 若要拷贝所有小写字母开头的隐藏文件,其命令为: #cp /root/.[a-z]* /temp
  • 430. 4. rm命令 命令名称: rm 功能: 删除文件 语法:rm 文件 描述:rm与DOS的del命令有些类似之处,不同的是,rm功能的强大与其相对杀伤力远不是DOS的del可以相比。只要是文件,不管是否隐藏,或是文件使用权限设置成只读,rm皆可删除,在此要注意的是已删除的文件是无法恢复的,所以在使用rm时要特别小心。 例如,我们删除temp目录下的file1文件,可用:$cd temp;rm file1 在Linux中要一次键入两个不同的命令时,只需在命令与命令
  • 431. 之间加上分号即可,这样Linux便会依照排列的先后次序来执行,在本例中,会先执行cd temp, 再执行 rm file1。 5. mv命令 命令名称: mv 功能: 文件更名或搬移 语法: mv 文件名称 搬移的目的地(或更改的新名) 描述:有的时候我们会做文件更名的操作,或是移动文件。其实文件更名与移动文件的操作原理是一样的,差别只是路径的不同。mv命令通常被用来移动文件,例如,把现在所在的目录中的netscape文件移到/usr内,可用:
  • 432. $mv netscape /usr 相关的命令还有:touch,file,diff等。
  • 433. 7.3目录和层次命令 同dos/windows操作系统一样,在linux系统中文件也是按目录保存在一个树形目录层次结构中的,目录层次的顶部是“根”目录,使用符号“/”。常用的目录和层次命令包括: 1. pwd命令 命令名称: pwd 功能:显示当前工作目录 语法:pwd 描述:pwd命令显示当前目录在文件系统层次中 的位置。
  • 434. 2. cd命令 命令名称: cd 功能: 切换目录 语法:cd 目录名称 描述:cd除了有切换目录的功能外,还有一个功能就是不管在哪个目录内,只要输入cd命令不用接任何参数,就可回到用户目录(home directory)内。
  • 435. 3. mkdir、rmdir命令 命令名称: mkdir/rmdir 功能: 创建目录和删除目录 语法: mkdir 目录名称 rmdir 目录名称 描述:在Linux中用mkdir命令,后面输入欲创建的目录名即可在当前目录中建立一个新目录,用rmdir并指定欲删除的目录即可删除指定的目录,操作方法与DOS中的md、rd是完全相同的,差别只是命令的名称不同而已。另外,在使用rmdir时,要确保该目录内已无任何文件存在,否则该命令不成功。
  • 436. 4. cp命令 命令名称: cp 功能: 带目录拷贝 语法:cp -r 目录 目的目录 描述:假如要拷贝一个目录,但该目录内还有好多个子目录的话,可以使用选择项“-r”,来拷贝目录内的子目录及文件,并且在拷贝时会自动建立目录,而此功能就相当于DOS内的 xcopy。例如,要将root目录内的所有文件(包括目录),但不包括隐藏文件,拷贝至根目录下的temp内,其作法为: #cp -r /root/* /temp
  • 437. 若要拷贝所有小写字母开头隐藏文件(包括隐藏目录)的话,其作法为: #cp -r /root/.[a-z]* /temp 5. rm命令 命令名称: rm 功能: 删除目录 语法:rm -r 目录 描述:选择项“-r”,与cp中的“-r”有类似的功能,它指在删除目录的同时一并删除目录内的子目录及文件,这个功能相当于DOS中的deltree功能,通常在使用deltree时会有提示信息,但在Linux中使用rm没有任何的提示信息,值得注意的是已删
  • 438. 除的文件是无法挽救回来的,所以在使用rm时要特别小心。当某个目录不再需要,例如,要删除temp目录,可以用下面的命令: #rm -r /temp 6. mv命令 命令名称: mv 功能:目录更名或搬移 语法: mv目录名称 搬移的目的地(或更改的新 名) 描述:有的时候需要做目录更名的操作,或是移动目录。目录更名与移动目录操作原理是一样的,差别只是路径的不同。例如,要把现在所在的目录
  • 439. 中的user1目录移到/home内,可用: #mv user1 /home 7.4 查找命令 1. find命令命令名称: find 功能:搜寻文件与目录 语法:find 目录名 选项 常用选项有: -name filename按名字查找 -type x 查找类型为x的文件(x包括:b,c,d,f, l等) user username 查找属主为username的文件
  • 440. -atime n 查找n天以前被访问过的文件 -mtime n 查找n天以前被修改过的文件 -cmin n 查找n分钟以前被修改过的文件 -exec cmd {} 对查找出来的文件执行cmd命令,{}表示找到的文件,命令要以“\\;”结束。 范例如下: $find /home/lin -name hash 在 /home/lin 目录下找寻名为 hash 的文件 $find / -name fs* -print 从 / 根目录开始搜寻所有以 fs 开头的文件,然后用参数 -print 印出符合条件的文件路径。 $find. -name *.c -exec rm-f{ }\\;
  • 441. 表示在用户当前的目录,搜寻所有以 .c 为结尾的文件名*.c,然后用参数 -exec 执行 rm-f{ }\\; 删除全部以 .c 结尾的文件(注意大括号里面没有空格)。 相关的查找命令还有:locate,whereis 2. grep命令 命令名称: grep 功能:在文件中查找字符串 语法:grep 字符串 文件名 范例如下: $grep tigger file1 在 file1文件中找寻tigger字符串
  • 442. $grep "big tigger" file1 在 file1文件中找寻 big tigger字符串。 另外,grep 命令还可以用于查找用正则表达式所定义的目标。正则表达式包括字母和数字,以及那些对grep有特殊含义的字符。比如, ^ 指示一行的开头 $ 指示一行的结束 . 代表任意单一字符 * 表示匹配零个或多个*之前的字符 范例如下: $grep ′^b′ file1
  • 443. 查找文件file1中所有以b开头的行。 $grep ′b$′ file1 查找文件file1中所有以b结尾的行。 $grep ′an.′ file2 查找文件file2中所有以an为头两个字符的3个字符,包括any,and等。
  • 444. 7.5 目录和文件安全性 Linux系统中每一个文件或目录都明确地定义其拥有者(owner)、组(group) 和它的使用权限等。用户可用下面的命令规定自己主目录下的文件权限,以保护自己的数据和信息,防止他人非法使用。 1. chown命令 命令名称: chown 功能: 改变文件拥有者 语法: chown 用户账号 文件或目录名称 使用人: 该文件或目录的拥有者和root 用户
  • 445. 描述:如果(假设账号是xLinux1)有一个名为file.list的文件,其拥有权要给予另一位账号为xLinux2的同事,则可用chown来完成此功能,当改变完文件拥有者之后,该文件虽然在xLinuxl的home目录下,但该用户已经无任何修改或删除这个文件的权限了,这点读者应特别注意。范例: - -rw------1 xLinux1 users 6 Oct 4 12:50 file.list $ chown xLinux2 file.list -rw------1 xLinux2 users 6 Oct 4 12:50 file.list
  • 446. 2. chgrp命令 命令名称: chgrp 功能: 改变文件的所属组 语法: chgrp 组名称 文件或目录名称 使用人: root 描述: 该命令和chown用法一样,其功能是把文件或目录所属组改成另一个组。 范例: - -rwxr-x--- 1 root bin 11700 Oct 12 06:48 shutdown* # chgrp system /sbin/shutdown
  • 447. 执行chgrp把shutdown所属组改成system组 - -rwxr-x--- 1 root system 11700 Oct 18 06:48 shutdown * 3. chmod命令 命令名称: chmod 功能: 修改文件的权限 语法: chmod 权限参数 文件或目录名称 使用人: 每一位用户 描述: 前面在介绍ls命令时,已经介绍文件的权限形态,例如 –rwx-------。要设置这些文件的形态就用 chmod这个命令来设置,然而在使用chmod 之前需要先了解权限参数的用法。权限参数可以有两种使用方法:英文字母表示法和数字表示法。
  • 448. (1) 英文字母表示法 一个文件用十个小格位记录文件的权限,第一小格代表文件类型。“-”表示普通文件;“d”表示目录文件;“b”表示块特别文件;“c”表示字符特别文件。接下来是每三小格代表一类型用户的权限。前三小格是用户本身的权限,用u代表;中间三小格代表和用户同一个组的权限,用g代表;最后三小格代表其他用户的权限,用o代表。即:-rwx-------属于用户存取权限,用u代表;---rwx---属于组用户存取权限,用g代表。-------rwx属于其他用户存取权限,用o代表。而每一种用户的权限就直接用r、w、x来代表对文件可读、可写、可执行,然后再用 + , - 或 = 将各类型用户代表符号u、g、o和 rwx3个字母链接起来即可。
  • 449. 范例: - -rwx-- chmod u+rwx file1 用户本人对file1可以进行读写执行的操作;- -rw-- chmod u-x file1 删除用户对file1的可执行权限;  -rw-rw-r-- chmod g+rw,o+r file1 同组用户对file1增加权限为能读写,其他用户则只 能读。
  • 450. (2) 数字表示法 数字表示法是用三位数字XXX,最大值为777来表示的。第一个数字代表用户存取权限,第二个数字代表同组用户使用权限,第三个数字代表其他用户存取权限。前面介绍的可读的权限r用数字4表示,可写的权限w用2表示,而可执行的权限x用1表示,即: r=4 w=2 x=1 假设用户对file1的权限是可读可写可执行rwx,用数字表示则把4、2、1 加起来等于7,代表用户对file1这个文件可读可写可执行, 这里rwx等价于 4+2+1=7。
  • 451. 至于同组用户和其他用户的权限,就顺序指定第2位数字和第3位数字即可。如果不指定任何权限的话,就要补0!下面举几个范例就明白了,请大家注意数字的变化。 范例:  -rwx-------chmod 700 file1 指定用户本人对file1的权限是可读,可写,可执行; -rw------- chmod 600 file1 指定用户本人对file1的权限是可读,可写; -rwxrwxrwx chmod 777 file1 指定所有用户对file1的权限是可读,可写,可执行。
  • 452. 总之,数字表示法就是将3位数字分成3个字段,每个字段都是4、2、1相加任意的组合。 相关的命令还有:umask
  • 453. 7.6磁盘存储命令 硬盘空间是一个有限的资源,用户用下面的命令可以随时了解当前硬盘空间的使用情况。 1. df命令 命令名称: df 功能: 显示磁盘的使用 语法: df [可选参数] 例如: $df -k 显示系统所配置的每一个磁盘当前被占用的空间 大小。
  • 454. 2. du命令 命令名称: du 功能: 显示目录的使用 语法: du [可选参数] 例如: $du 按块(512字节)显示一个目录及其所有子目录 的使用。
  • 455. 1. ps命令 命令名称: ps 功能: 查询正在执行的进程 语法: ps [可选参数] 描述:ps命令提供Linux系统中正在发生的事情的一个快照,能显示正在执行进程的进程号、发出该命令的终端、所使用的CPU时间以及正在执行的命令。 例如: $ps aux7.7 进程命令
  • 456. 2. kill命令 命令名称: kill 功能: 终止正在执行的进程 语法: kill 进程号 例如: $kill -9 PID# 无条件删除进程号为PID#的进程。 相关命令还有:w,who等
  • 457. 7.8联机帮助命令 各种在线帮助是学习Linux很好的工具, 以下是常用的在线辅助工具: 1. man 命令 系统上几乎每条命令都有相关的Man(manual) page。 在有问题或困难时, 可以立刻找到这个文件。 例如, 如果使用ls命令时遇到困难, 可以输入: $man ls 系统就会显示出 ls 的 man page。
  • 458. 由于man page是用less程序来看的, 所以在man page里可以使用less的所有选项。 在less中比较重要的键有: q退出 Enter一行行地下翻 Space一页页地下翻 b往上翻一页 /往后寻找一个字符串和Enter键来寻找字符串 n寻找上一次查寻的下一个符合的字符串
  • 459. 2. 内包的文件 (DOC) 许多软件包都提供有readme文件和其他文档。 专为Linux制作的包的文件定义了一个标准的地方存放这些文件, 每个包的文件都放在 /usr/doc下的一个子目录中。子目录名称取决于软件包的名称和版本号。 例如zip软件包可能是2.1版。 那么,它的文件就放在/usr/doc/zip-2.1目录。大多数情况, /usr/doc中的文件是ASCII码。 你可以用more filename 或者less filename来阅读。
  • 460. 3. Howto和FAQ 如果你安装了它们,目录/usr/doc/Howto包含了你的Linux 光盘发行时所能找到的所有Howto。 为了节约空间,它们用gzip命令进行了压缩, 所以在阅读之前必须解压缩。 有一种方法可以阅读压缩的Howto, 不会让解压缩后的文件搞乱你的硬盘, 即使用 zless: $zless 3DfxHowto.gz zless使用和less一样的键, 所以可以在Howto中容易地翻页。 /usr/doc/FAQ 包含了ASCII格式(和部分html格式)的一些FAQ(常见问题)。 可以用more 或者 less来阅读。
  • 461. 7.9 小结 本章主要介绍了Linux系统常用的一些命令,包括如何登录和退出系统、创建及删除目录、文件管理等。为了使用Linux,首先需要有一个合法的账号,其次要学会使用man命令,以便随时获取需要的帮助信息。
  • 462. 习题 7-1 登录进入系统,在你的根目录下建一个子目录tmp。查看同时系统上正在运行哪些进程。 7-2 将/etc/passwd文件拷到你自己建的tmp子目录下,使用grep查看你的账号是不是在这个文件中。 7-3 删除你自己建的tmp子目录。
  • 463. 第8章 使用vi编辑文件8.1 vi的启动与退出 8.2 vi的两种模式 8.3 基本vi命令 8.4 使用vi查找和替换 8.5 编辑多个文件 8.6 小结 习题
  • 464. vi的名字取自于visual,意为“直观”,它是一个全屏幕文本编辑程序。在Linux系统中vi是最常用的编辑程序,它的文本编辑功能十分强大,但使用起来比较复杂。初学者可能感到困难,经过一段时间的学习和使用后,你就会体会到使用vi非常方便。Linux系统中的vi其实是vim。vi与vim的用法很像,因为vim是vi的增强版,所以vi的功能vim都有,而且vim新增了许多vi没有的功能,它比vi容易使用。本章介绍vi编辑程序的两种工作模式,即命令模式和输入模式。
  • 465. 1. vi的启动 输入vi命令后,便进入全屏幕编辑环境,此时的状态为命令模式。 (1) vi 进入vi的一个临时缓冲区,光标定位在该缓冲区第1行第1列的位置上。 (2) vi file1 如果file1文件不存在,将建立此文件;如该文件存在,则将其拷贝到一个临时缓冲区。光标定位在该缓冲区第1行第1列的位置上。8.1 vi的启动与退出
  • 466. (3) vi+file1 如果file1文件不存在,将建立此文件;如该文件存在,则将其拷贝到一个临时缓冲区。光标定位在文件最后1行第1列的位置上。 (4) vi+Nfile1(N:为数字) 如果file1文件不存在,将建立此文件;如该文件存在,则将其拷贝到一个临时缓冲区。光标定位在文件第N行第1列的位置上。 (5) vi+/string file1 如果file1文件不存在将建立此文件;如该文件存在则将其拷贝到一个临时缓冲区。光标定位在文件中第一次出现字符串string的行首位置。
  • 467. 2. 退出vi 建议在退出vi前,先按ESC键,以确保当前vi的状态为命令方式,然后再键入“:”(冒号),输入下列命令,退出vi。 (1) :w 将编辑缓冲区的内容写入文件,则新的内容就替代了原始文件。这时并没有退出vi,必须进一步输入下述命令才能退出vi: :w filename(存入指定文件) :q
  • 468. (2) :wq 即将上面的两步操作可以合成一步来完成,先执行w,后执行q。 (3) :x和zz(注意:zz前面没有“:”) 功能与(2)等价。 (4) :q!(或:quit) 强行退出vi,使被更新的内容不写回文件中。仅键入命令:q时,如vi发现文本内容已被更改,将提示用户使用“:quit”命令退出。
  • 469. 8.2 vi的两种模式 当vi工作在命令模式下,输入的字符被视为执行特定vi功能的命令;而工作在输入模式下,输入的字符是编辑文件的正文。命令模式是vi的默认模式,命令模式下输入英文大小写字母的含义是有区别的。两种模式的切换见图8.1。 图8.1 模式转换示意图
  • 470. 在命令模式下,你所能进行的操作有移动光标在屏幕上的位置,标记、删除、移动、复制字符或文本区块,还可以将文件写入或退出编辑器,亦可设置编辑环境,如寻找字符串、列出行号等。此外在系统提示符下输入vi及文件名称后,即进入vi全屏幕编辑画面(命令模式)。 只有在输入模式下,才可进行文字输入,按ESC键可以回到命令模式。在命令模式下可按“i”或“a”或“o”等键进入输入模式。 i——在目前光标前插入所要输入之文字。 a——在目前光标后开始输入文字。 o——在当前光标所在行下新增一空行,并从行首开始输入文字。
  • 471. I——插于行首。 A——插于行尾。 O——在当前光标所在行上新增一空行,并从行首开始输入文字。 按下ESC键随时可返回vi的命令模式。如果不能确定现在vi是在哪个模式下,按下ESC键以使其在命令模式下,然后再从这里继续;如果按下ESC键时已经在命令模式了,系统会鸣叫且屏幕闪一下,通知你已在命令模式中。
  • 472. 8.3 基本vi命令 1. 移动光标 移动光标h、j、k、l:分别控制光标左、下、上、右移一格。 Ctrl+b: 上滚一屏。 Ctrl+f: 下滚一屏。 Ctrl+d: 下滚半屏。 Ctrl+u: 上滚半屏。 G: 移到文件最后。 w: 移到下个字的开头。 b: 跳至上个字的开头。
  • 473. 2. 删除 x: 删除当前光标所在后面一个字符。 #x: 删除当前光标所在后面#个字符。例如,5x表示删除5个字符。 dd: 删除当前光标所在行。 #dd: 删除当前光标所在后面#行。例如,5dd表示删除自光标算起的5行。 :l,#d: 例如,:1,12d表示删除自行1至行12的文字。 X: 删当前光标的左字符。 D: 删至行尾。
  • 474. 3. 更改 cw: 更改光标处的字到此单字的字尾处。 c#w: 例如,c3w表示更改3个字。 cc: 修改行。 C: 替换到行尾。 4. 取代 r: 取代光标处的字符。 R: 取代字符直到按ESC为止。
  • 475. 5. 复制 yw: 拷贝光标处的字到字尾至缓冲区。 P: 把缓冲区的资料贴上来。 yy: 拷贝光标所在之行至缓冲区。 #yy: 例如,5yy,拷贝光标所在之处以下5行至缓冲区。 6. 复原 u: 复原至上一操作。 g: 列出行号,及相关信息。 7. 列出行号 :set nu (nu为行数)
  • 476. 8. 寻找字符串 /word由首至尾寻找“word”字符串,按n可往下继续找。 ?word由尾至首寻找“word”字符串,按N可往前继续找。 9. 跳行 :100可跳至第100行。 10. 重复上一个命令 .重复上一个命令。
  • 477. 8.4 使用vi查找和替换 vi提供了几种定位查找一个指定的字符串在文件中位置的方法。同时还提供一种功能强大的全局替换功能。 1. 查找一个字符串 一个字符串是一行上的一个或几个字符。 为查找一个字符串,在vi命令模式下键入“/”,后面跟要查找的字符串,再按回车。vi将光标定位在该串下一次出现的地方上。键入n跳到该串的下一个出现处,键入N跳到该串的上一个出现处。 为了在文件中回头查找,使用?代替/。在此情况下,键入n跳到该串的上一个出现处,键入N跳到该串的下一个出现处。
  • 478. 如果vi找到要求的串,光标会停留在该串第一次出现的地方。如果没有找到该串,vi会在屏幕的最后一行显示pattern not found。 查找通常是区分大小写的,如果希望vi在查找过程中忽略大小写,则键入:set ic。要使其变回默认状态,则键入:set noic。 某些特殊字符(/&!.^*$\?)对查找过程有特殊意义,因此如果这些字符出现在查找串中必须进行转意。为转意一个特殊字符,需要在该字符前面加一个反斜杠(\)。例如,要查找字符串anything?,则键入/anything\?再按回车键。
  • 479. 2. 精确查找字符串 在vi中可以通过在字符串中加入如下特殊字符,从而使得查找更加精确。 匹配行首,字符串要以^开头 匹配行尾,字符串要以$结束 匹配词首,字符串的串首键入\< 匹配词尾,字符串的串尾键入\> 匹配任意字符,字符串的要匹配的位置键入一个点(.) 例如, 要查找一个以search为行首的行,则键入/^search ,要查找一个以search为行尾的行,则键入/search$。
  • 480. 3. 替换一个字符串 替换字符串是以查找为基础,所有用于查找的特殊匹配字符都可以用于查找和替换。替换时要指定替换的范围(1,n),1和n指行号,n为$时指最后一行。s是替换命令,g代表全程替换。例如, :l,$s/patternl/pattern2/g——将行l至结尾的文字,patternl的字符串改为pattern2的字符串,如无g则仅更换每一行所匹配的第一个字符串,如有g则将每一个字符串均做更换。
  • 481. 8.5 编辑多个文件 1. 将一个文件插入另一个文件中 将另一个文件filename插入当前文件的line#行位置。命令格式, :line# r filename 例如,将文件file1插入到当前文件的当前光标位置,键入, :r file1
  • 482. 2. 编辑一系列文件 要想编辑多个文件,需要在vi命令之后列多个文件名,中间用空格分开。键入:n进入下一个文件。要想跳转到下一个文件,而不保存对当前文件所做的修改,则键入:n!来代替:n。 vi file1 file2 file3 3. 文件之间复制行 为将行从一个文件file1复制到另一个文件file2,先编辑第一个文件file1,用#yy(#代表数字)把要复制的行拷贝到缓冲区,不退出vi,编辑另一个文件,键入, :n file2 再按p键,把缓冲区中的内容贴在当前光标位置。
  • 483. 8.6 小结 本章主要介绍了vi编辑器的使用,重点要掌握vi的两种操作模式:输入模式和命令模式,并熟练掌握命令模式下的插入、修改、删除、拷贝粘贴,以及查找和替换命令。
  • 484. 习题 8-1 vi中拷贝一行文字并粘贴到另一位置用什么命令? 8-2 vi中把某个字符串全程替换为另一个字符串的命令是什么? 8-3 使用vi编辑器在目录里创建一个文本文件,然后输入一篇英文文章,并练习使用各种编辑命令。
  • 485. 第9章 shell编程9.1 shell概述 9.2 shell的基本功能 9.3 shell启动及其命令 9.4 shell命令的集成 9.5 shell变量 9.6 shell的控制结构 9.7 shell的运行环境 9.8 shell应用实例 9.9 小结 习题
  • 486. shell是一种命令语言,同时又是一种程序设计语言。shell的语言处理能力,使得用户能够方便地定义各种变量、参数,并使用各种控制语句编写复杂的命令程序完成多种工作。本章介绍shell、shell程序设计语言、shell的运行环境及shell程序的调试。
  • 487. 9.1 shell概述 9.1.1 什么是shell shell是一种命令解释程序(命令解释器),shell解释用户输入的命令行,提交系统内核处理,并将结果返回给用户。与Linux命令一样都是实用程序,但两者又有区别。一旦用户注册到系统后,shell就被系统装入内存,并一直运行到用户退出系统之止;而一般命令仅当被调用时,才由系统装入内存执行。 shell本身也是一种可编程的程序设计语言。用shell写的程序(shell脚本)相当于dos/windows下的批处理文件,它可以简单到只有一条命令,也可以复杂到包括大量循环、条件语句、数学运算、控制结构,也可以是介于两者之间的程序。
  • 488. 9.1.2 shell程序语言的特点 shell允许通过编程来完成复杂的功能处理,但其作为语言与高级语言相比较具有不同的特点: (1) shell是解释性的,多数高级语言是编译性的; (2) shell语言与高级语言处理的对象不同; (3) shell与系统有密切的关系; (4) shell易编写、调试、灵活性较强,但速度低; (5) shell作为命令级语言,命令组合功能很强。
  • 489. 9.1.3 shell的版本 shell有两种主要语法类型: Bourne shell和C shell,彼此不兼容。Bourne shell家族:sh ksh bash psh zsh;C shell家族:csh tcsh。 其中bash和 zsh在不同程度上支持 csh 的语法。 这里,我们再着重介绍一下bash的特点: (1) 自动补全功能 假设要输入的命令很长,或者命令后面要给的文件名很长。这个时候只要按一个Tab键,bash就会在可能的命令或文件名里面找寻匹配的命令,找到的话就会自动帮你补齐。
  • 490. (2) 命令行编辑程序 bash的命令行编辑是在提示符下,可对未执行的命令字符任意地修改。 (3) 命令历史(command history) 所谓的命令历史就是把曾经输入过的命令记录起来,方便日后的查询与使用。只要按向上键就可以调出前一个命令,再按一次向上键就可以调出更前一个命令,依此类推,用向下键可以回到下个命令,所以用上、下键就可以选择以前输入过的命令。
  • 491. 9.2 shell的基本功能 9.2.1 程序的运行 当用户输入一行命令后,shell负责解释、分析输入的内容,并且决定做什么,同时替系统内核删除命令行中不必要的信息。命令是一个可执行的Linux命令、程序、工具或shell脚本。 例1: $ls -l file1 file2 file3 例2: $echo ′Welcome to Tsinghua University.′ 例3: $echo Welcome to Tsinghua University. 注意: 例2和例3的结果是完全一样的。
  • 492. 9.2.2 使用保留字和元字符 shell有一些具有特殊意义的字(保留字) ,如在shell脚本中,像do、done、for、while等保留字控制循环操作,if、then、else等保留字进行条件控制。保留字随shell的不同而不同。 在Linux系统里,有一组特殊意义字符,这就是所谓的元字符(通配符)。 现在列出一些常用的通配符的意义,供参考。 .. 上一层目录,与cd命令配合用得比较多 . 目前工作的目录 * 任意长度的字符 ? 长度为一个的任意字符
  • 493. [..] 括号内的一个字符 \m 等于某个通配符,如*、?等 [a-z]* 小写字母开头的所有字符串 \ 转义符号,用以解除特殊字符的特殊意义 ~ 用户目录 ; 分隔符,当命令行有多个命令时,做分隔用 $ BourneShell的提示符,同时也作为shell语言的位置变量参数 # 做注释用 | 建立一个管道,使一命令的输出作为另一个命令的输入 & 将命令以后台方式执行
  • 494. > 将命令的输出重导入文件中 < 将命令的输入流指定为由文件中加载,和>相反 >> 将命令的输出加在一个已经存在的文件后面 {..} 括号内的一个字符串 例: $ls -x t*显示当前目录下以t打头的所有文件。
  • 495. 9.2.3 变量、文件名的替换 1. 变量的替换 shell允许对变量赋值。shell一旦在命令行中发现$变量名时,将在$变量名的位置上用以前赋给该变量的值替代$变量名。 例: $myhome=/usr/app1 $echo $myhome /usr/app1 $ls -x $myhome file1 file2 file3 file4
  • 496. 2. 文件名的替换 shell在命令行中将文件名进行替换。事实上,shell在确定要执行的程序名和它的自变量之前,要对命令行扫描,找出元字符进行相应的文件名的替换。 例: $ls -x file1 file2 file3 file4 $echo* file1 file2 file3 file4
  • 497. 9.2.4 输入输出重定向(改向) shell处理命令行的输入输出重定向,它扫描命令行中特殊改向字符“>”、“<”、“>>”、“<<”,将输入或输出改向到指定的文件中。 例: $echo “Please call me:62781849” > msg $cat msg Please call me:62781849 注意: 就程序或命令本身而言,它并不知道其标准输出已被改向,只是简单地按照自身的方式向标准输出输送信息。
  • 498. 正如shell扫描命令行查找重定向字符一样,它也查找管道字符“|”。对于所发现的每个管道字符,它将管道字符前面的命令的标准输出连接到管道字符后面的命令的标准输入中,然后启动两个程序的执行。 例: $w|wc -l(假设有8个用户上机) 8
  • 499. 9.2.5 运行环境的控制 当用户登录到Linux系统中,系统启动一个交互式的shell命令解释器(称为注册shell)。该shell为此用户创建工作环境。shell提供了一定的命令,允许用户对自己运行的环境进行控制,即对运行环境实现客户化。用户的运行环境包括:主目录、终端类型、输入命令提示符、查找命令的路径名、以及其他全局变量等。例如,Bourne again Shell、Bourne Shell、Korn Shell和C Shell的环境文件分别为.bash-profile、.profile、.kshrc和.cshrc。
  • 500. 9.2.6 支持shell的编程 shell除了具有命令解释器的功能外,它本身就是一种程序设计语言,这种语言也由shell解释执行的。用户可以在文件中编写一组shell命令,该文件称为shell脚本或shell程序。通过把命令、变量赋值及条件控制语句结合起来,用户就获得了一个强大的编程工具。需要说明的是,在Linux系统本身就存在大量的shell程序,用于各种管理和应用。
  • 501. 9.3 shell启动及其命令 9.3.1 shell的启动 1.系统在用户登录时启动shell 在Linux系统引导过程中,首先启动init进程以查询终端的各个端口及其特性,当发现活动的终端时,调用getty进程。接着getty进程在接受用户名和口令后,调用login进程。login进程负责验证用户身份,验证后把控制权交给shell程序。shell根据环境文件建立系统范围内的工作环境和该用户自己的工作环境,最后显示命令提示符(#、$、%)。 在/etc/passwd文件中指定要启动的shell,如下所示:
  • 502. root:x:0:0:root:/root:/bin/bash john:x:201:Certer′starf:/home:/bin/sh 2. 命令行状态下的交互shell启动 在系统中可能有多种版本的shell存在,可通过相应的命令来启动,如: $bsh $ksh $sh 3. 执行用户命令时启动shell(子shell) 由系统生成新的子shell来执行该命令。
  • 503. 9.3.2 命令的查询 环境变量PATH的构成决定了寻找shell命令和其他程序的途径,是影响shell程序效率的主要因素之一。PATH变量设置要考虑以下几点:在PATH变量中,命令使用得多的程序目录应放在前面,极少用目录不设在PATH变量中。在shell程序内用得较多的程序目录应加在变量PATH中。并且PATH应尽可能地短,不要出现重复的目录。还要尽量避免查询大目录,如需设置,将其路径放在PATH路径的最后位置。 例: PATH=/bin:/usr/bin:/etc:.
  • 504. 9.3.3 shell常用的命令 Linux系统通常提供了许多命令以方便用户与系统的交互对话。这些命令的选项较多,并且可利用命令的集成(如输入输出改道、管道机制)及程序设计功能组合成许多命令。 Linux有丰富的shell命令,大致划分为以下几类:目录操作与管理、文件操作与管理命令、系统管理与维护、用户管理与维护、系统状态、进程管理、通讯命令、其他命令。例如, awk cat chmod chown cp cron date df diff du echo expr file find grep init kill ln login ls mail make man mkdir mv nohup pg ps pwd read rm wc
  • 505. 通常情况下,在用户输入一个命令(非内部命令)时,注册shell首先通过查询路径查找该命令,然后生成出一个副本(称为该shell的子shell),由子shell来负责解释执行这个命令。在命令执行过程中,注册shell(父shell)等待子shell的执行而进入睡眠态,一旦子shell执行完毕,子shell将唤醒注册shell(父shell),而自己的生命周期到此结束。
  • 506. 9.3.4 shell的内部命令 内部命令构造在shell的内部。内部命令比非内部命令的执行速度要快。因此,编写shell程序时应尽量地使用shell的内部命令。shell常用的内部命令有: # 注释命令,#后面的内容作为注释信息。 : 空命令,通常放在一行的最左边,实际不做任何命令,只返回出口代码0。 其他命令有:cd,eval,set,unset,exec,exit,if,else,for,case,while,until,continue,break等。
  • 507. 9.4 shell命令的集成 9.4.1 元字符和文件名生成 1. UNIX元字符(通配符)的定义 * 匹配任何字符串,包括空字符串; ? 匹配任何单个字符; [.,-,!] 按照范围、列表或不匹配等形式匹配指定的字符; \ 转意符,使元字符失去其特殊的含义。 例: [a-d,x,y] 匹配字符a、b、c、d、x、y; z* 匹配以字符z开始的任何字符串;
  • 508. x?y 匹配以x开始、以y结束、中间为任何单个字符的字符串; [!Z] 匹配不为Z的单个字符。 2. 元字符作为文件扩展名的使用 例: [a-f]* 匹配字符a到字符f开头的文件名,如abc,d2,e3.c,f.dat; *z 匹配以字符z结尾的任何字符串,如win.z,core.zz,a-c-5z; rc?.d 匹配以rc开始、以.d结束、中间为任何单个字符的文件名,如rc0.d,rc2.d,rcS.d; *[!o] 匹配不以o结尾的文件名。
  • 509. 9.4.2 管道和命令表 在shell中有两种结构类型:管道线和命令表。当shell检测到一个管道操作符时,就建立一个系统管道文件,这是一个先进先出的数据结构,它允许在同一时刻对管道线上的命令或程序进行读和写,即允许两个无关的命令通过管道连接交换信息。 1. 管道的概念 管道:是一个命令的标准输出与另一个命令的标准输入之间的连接,不经过任何中间文件; 管道线:是由管道操作符分隔的一个命令序列,最简单的管道线是一个简单命令; 管道操作符:用符号“|”表示。
  • 510. 例: w|wc -l ps aux|grep ftp 2. 命令表的概念 命令表:一串管道线构成了一个命令表,最简单的命令表是一个管道线,一个命令表送回的值是该命令表中最后一个管道线的出口状态。 管道线分隔符:分隔命令表元素,确定管道线执行的条件。各分隔符含义如下: ; 表示按顺序执行管道线; && 表示根据条件(true),执行其后面的管道线; ‖ 表示根据条件(false),执行其后面的管道线;
  • 511. & 表示前面的管道线在后台(异步)执行。 例1: 四个管道线构成一个命令表 ls -l /tmp /root w|wc -l ps 例2: 与例1等价 ls -l /tmp /root ;w|wc -l ;ps 例3: sys-account &
  • 512. 9.4.3 命令组合 命令组合有两种形式:{命令表}和(命令表),前者只在本shell中执行,不产生新的子进程;后者要产生新的子进程来执行命令表。 例1: { cd mydoc; rm junk;} 该命令表只能在当前shell下执行,先进入目录mydoc,然后执行rm命令,执行完毕后,当前目录已改变为mydoc。 例2: (cd mydoc; rm junk;) 当前shell要生成一个子shell进程,由该子shell来执行命令表。子shell完成操作后,自然消亡,而其父shell进程的当前路径并没有变化。
  • 513. 9.4.4 命令替换 当一个字符串被括在反撇号“ ` ”中时,该字符串将作为命令被shell解释执行,即用命令的执行结果替换这个字符串本身。要注意反撇号与单引号的区别。 例1:$ now=′date′ $ echo $now date $ now=`date` $ echo $now 1998年 10月 28日 星期三 17时 51分 56秒 CST 例2:$ count=10 $ count=`expr $count+1` $ echo $count 11
  • 514. 9.4.5 输入、输出重定向 1. 使用标准改向符进行重定向(改向) < 输入改向 << 追加输入改向 > 输出改向 >> 追加输出改向 2. 使用标准文件描述字进行重定向(改向) 在Linux系统中,定义了用于输入、输出的标准文件,其文件描述字0为进程的标准输入、文件描述字1为标准输出、文件描述字2为标准错误输出。 3. 标准错误输出的改向(>、>>) 格式为:
  • 515. command 2 >file command 2 >>file 例1: 将myfile1作为sort的输入。 sort myfile2 例3: 将ls \|l的输出追加到myfile3文件中。 ls -l>>myfile3 例4:将错误输出改向到err-file文件。 $myprog 2>err-file 例5:将标准输出和错误输出改向out文件。 $myprog >out 2>>out $myprog >out 2>>&1
  • 516. 9.5 shell变量 9.5.1 shell变量描述 shell实际上是基于字符串的程序设计语言,但也有变量。shell变量能够而且只能存储正文字符串,即它只有一种类型的变量即串变量。但从赋值的形式上看,则可以分成四种类型的变量或变量形式。变量的名字必须以字母或下划线开头,可以包括字母、数字和下划线。 9.5.2 用户自定义变量 用户自定义变量语法格式:name=string,赋值号“=”两边不允许有空白符。 例:
  • 517. nodehost=beijing.UUCP path=/bin:/usr/bin:/etc/bin count=10 允许多个赋值操作,按从右到左的顺序进行。 例: $A=$BB=abcC=″OK″ $ echo $A $B $C abc abc OK 当引用一个未设置的变量时,其隐含值为空。 例: $ echo ″$mail is path of mailbox″ is path of mailbox
  • 518. 如果用双引号“”将值括起来,则括起来的字符串允许出现空格、制表符和换行符等特殊字符,而且允许有变量替换。 例1:$ MAIL=/var/mail/fk $ var=″$MAIL is path of mailbox″ $ echo $var /var/mail/fk is path of mailbox 例2: $ str=″This is \n a book″ $ echo $str This is a book
  • 519. 如果用单引号‘’将值括起来,则括起来的字符串允许出现空格、制表符和换行符的特殊字符,但不允许有变量替换。 例3: $ BOOK=″English book″ $ MSG=′$BOOK′ $ echo $MSG $BOOK 例4: $ msg=′ Today is Sunday′ $ echo $msg Today is Sunday
  • 520. 引用变量的值时,可以用花括号{}将变量名称括起来,使变量名称与它的后续字符分隔开,如果紧跟在变量名称后面的字符是字母、数字或下划线时,必须要使用花括号。 例5: $ str=′This is a string′ $ echo ″${str}ent test of variables″ This is a stringent test of variables $ echo ″$strent test of variables″ test of variables
  • 521. 可将变量设置为只读形式,格式为,readonly 变量名1 变量名2 例6: $ ux=UNIX.SUN $ readonly ux $ ux=UNIX.SCO ux: is read only 查看只读形式的变量,格式为readonly 例7: $ readonly readonly ux
  • 522. 9.5.3 位置变量 位置变量顾名思义是与变量所在位置有关的变量,这是一种特殊的变量。当一个shell过程被调用时,shell隐含地为它建立一系列的位置变量。这种位置变量是系统预定义好的,可以直接引用。如命令行的shell过程名本身被指定为位置变量$0,第一个命令参数为$1,……,第九个命令参数为$9。 例: ls / /bin /etc /usr/bin /dev $0 $1 $2 $3 $4 $5
  • 523. 1. 内部命令shift 的作用 当位置变量个数超出9时,就不能直接引用位置大于9的位置变量了,必须用shift命令存取。每执行一次shift命令,删除$1位置变量,并使其他的所有位置变量向左移动一个位置。 例: $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 myprog a b c d e f g h i j shift b c d e f g h i j shift c d e f g h i j shift d e f g h i j
  • 524. 2. 用set命令进行强制性赋值 位置变量可以使用set命令进行强制性赋值。 例: set Sun Mon Tue Wed Thu Fri Sat 结果$1 $2 $3 $4 $5 $6 $7 注意: $0是不能用这种方法赋值的。
  • 525. 9.5.4 环境变量 shell执行环境由一系列环境变量组成,这些变量是由shell维护和管理的。所有这些变量都可被用户重新设置,变量名由大写字母或数字组成。 CDPATH 执行cd命令时使用的搜索路径; HOME 用户的home目录; PATH 寻找命令或可执行文件的搜索路径; PS1 主命令提示符,默认为“$”; PS2 从命令提示符,默认为“>”; TERM 使用的终端类型。
  • 526. 9.5.5 预定义的特殊变量 在shell中有一组特殊的变量,其变量名和变量值只有shell本身才可以设置。 “$#” 记录传递给shell的自变量个数。 例1: myprog a b c 则 $#的值为3 例2: if test $# -lt 2 then echo ″ two or more args required ″ exit fi
  • 527. “$?”取最近一次命令执行后的退出状态:执行成功返回码为0,执行失败返回码为1。 例: $test -r my-file(假设my-file文件不可读) $echo$? 1 “$$”记录当前shell的进程号。
  • 528. 9.5.6 变量替换 shell在遇到未设置的变量时,将其值作为空串处理。而在实际应用中,对于未设置的变量,用户可以根据需要采用不同的处理方式,这可通过变量替换来实现。变量替换提供了三种功能:允许替换未设置变量的隐含值;允许对未设置变量赋值;在访问未设置变量时,提示出错信息。格式为, ${var:-word} 例1: 假设$PARM未设置 $echo ″ The value of PARM is ${PARM:-undefined}″ The value of PARM is undefined $echo $PARM -
  • 529. 例2:假设$PARM未设置 $arg=${PARM:- ″ not defined ″} (注意: 双引号) $echo ′ $arg : ′$arg $arg : not defined 例3:对未设置变量赋值 $cat use.d sel=$1 :${sel∶=main}(注意: 此处的“:” 为空命令) echo ″ Your selection is $sel ″ $use.d programming Your selection is programming
  • 530. 注意: 变量替换的这种形式不允许使用位置变量,若要使用位置变量,则必须先将位置变量赋值给一中间变量,然后再对中间变量进行这种形式的替换。 例4:将例3中的空命令用中间变量替换。 $cat use.d sel=$1 my-sel=${sel∶=main} echo ″ Your selection is $my-sel ″ $use.d programming Your selection is programming
  • 531. 例5: 测试环境变量TERM是否设置。 $cat check.env : ${TERM:? ″ the TERM varible should be set ″ } 注意: 出错信息以一行长为限,且输出到标准错误输出上。
  • 532. 9.5.7 特殊字符的引用 在shell中所使用的许多特殊符号也可为其他目的所使用,因此当不需要引用这些字符的特殊含义时,就必须进行删除。消除特殊字符的含义有3种常用的方法,分别是转义符、单引号和双引号。 1. 转义符(\)的引用 使用转义符消除单个字符的特殊含义,即将紧跟在转义符后面的单个字符按字符本身的实际含义解释。 例:转义符具有续行功能 $ cat back.sh echo ″Enter your name: \\c″ read name echo Hello $name
  • 533. $ back.sh Enter your name: john Hello john 2. 单引号 (‘’)的引用 使用单引号消除被括在单引号中的所有特殊字符的含义,即单引号表示内容照原样不动。 例1: $echo ′type a $* please′ type a $* please 例2: 在指定的目录中,查找名字为 *.zh 或 $.sh文件。 $cat test.sh grep ′*.zh | $.sh′ $1
  • 534. 3. 双引号 (“”)的引用 使用双引号能消除被括在双引号中的大部分特殊字符的含义,不能消除的字符有:$、 ` 、″、 \。 例1:$echo ″ Type a \$*, please ″ Type a $*, please 例2: vdate= ″`date` is the system maintenance time ! ″ 例3: $cat share-file mkdir /tmp/fk chmod 755 /tmp/fk cp ″$@″ /tmp/fk chmod 777 /tmp/fk/*
  • 535. 4. 特殊字符串引用的例外 引用双引号、单引号和转意符都不能消除对echo命令有特殊功能的控制字串的特殊含义。这些控制字串是: \b 退格 \c 显示后不换行 \f 在终端上屏幕的开始处显示 \n 换行 \r 回车 \t 制表符 \v 垂直制表符 \ 反斜杠
  • 536. 9.6 shell的控制结构 9.6.1 条件与test命令 在程序设计语言中,作出决策的结构称为条件。在高级语言中决策的作出是依赖于基本运算的结果;在shell语言中,作出决策所依赖的条件是所执行命令的“出口状态”。 当shell命令或程序执行成功时,它返回一个“零”出口状态(即$?为零);如果执行的命令或程序出错时,则返回一个“非零”的出口状态(即$?不为零)。 除了一般命令的出口状态外,UNIX还提供了两个命令true和false的出口状态。true的出口状态为零;而false的出口状态为非零。shell将true和false命令作为恒真和恒假条件使用。
  • 537. 例: 判断所给出的参数是否为一个目录。 $cat check.dir test -d $1 && echo ″ $1 is a dictory ″ && exit 0 echo ″ $1 is not a dictroy ″ exit 1 在上例中,使用了exit命令。它是一个shell的内部命令,用于终止shell程序的执行。该命令可带一个定义出口状态值的自变量。 例: exit(0): 终止程序的执行,并返回零值; exit(1)或exit(x): 终止程序的执行,并返回非零值; 将命令返回零出口状态称为返回“真值”; 将命令返回非零出口状态称为返回“假值”。
  • 538. 1. test命令 test命令是shell程序设计的条件判断中最常用的测试命令,它有两种等价的格式: test expression或[expression](注意:[ ]中的空格) 其中expression就是要测试的条件。如果test计算expression的结果为真,则返回“零”出口状态,否则返回“非零”出口状态。test命令可用于对字符串、整数及文件进行各类测试。
  • 539. 2. test字符串测试表达式 例1: 两个字符串进行比较 $ user=smith $ test ″$user″= smith $ echo $? 0 $ test ″$user″ = tom $ echo $? 1
  • 540. 例2: 带有空格的字符串比较 $ month=″January ″ $ test ″$month″ = January $ echo $? 1 $ test $month = January $ echo $? 0 注意: shell在处理变量时,遇到有双引号将保留其内容,而省略双引号时,将滤去空格。
  • 541. 例3: 带有空格的字符串比较 $ a=″testing string″ $ test ″$a″ = ″testing string″ $ echo $? 0 $ test $a = ″testing string″ test: unknown operator string shell处理变量 $a 时,将其进行变量替换,然后将结果(testing string)传递给test,而test将string作为操作符来处理,因此出错。
  • 542. 例4: 带有空串(或未设置的字符串比较) $ name= $ test ″$name″ = smith $ echo $? 1 $ test $name = smith test: argument expected shell处理变量$name时,双引号将其括起的内容作为一个“位置持有者”来保留,并把该值传递给test,保证处理的正常执行。
  • 543. 例5: 带有空串的字符串比较 $ blanks=″″ $ test $blanks $ echo $? 1 $ test ″$blanks″ $ echo $? 0 shell处理变量$blanks时,将空格滤去,使其变为空串传递给test;而双引号保留 “位置持有者”的位置,其值为一个空格(空白符),传递给test。
  • 544. 例6: 带有算符的字符串比较 $ symvar=″=″ $ echo ″$symvar″ = $ test -z ″$symvar″ test: argument expected 出错的原因是“=”运算符比“-z”运算符的优先级要高,因此,test 命令期望在等号之后要有一个自变量。为避免上述问题发生,可用下面命令形式替换: $ test x″$symvar″ = x $ echo $? 1
  • 545. 3. 使用test测试字符串时要注意的问题 (1) 向test 传递的各自变量之间必须有空白字符,如果“=”与任一自变量之间没有空白字符就会产生错误。 (2) 在使用变量的值替换的自变量上,用双引号括起来十分必要,以保证test在变量的值为空时也能接收到该自变量,这是一种良好的shell程序设计风格。 (3) 在test命令的测试中,空格和引号是shell程序设计中经常发生错误的焦点,要特别引起注意。 (4) test命令对它的自变量非常讲究,在比较的串中出现运算符时,要考虑到运算符优先级的问题。
  • 546. 4. test命令可用于整数比较 首先要搞清楚整数比较的两个概念: shell并不区分放在shell变量中的值的类型,就变量本身而言,它存放的仅仅是一组字符串,即shell只有一种类型的变量——串变量;当使用整数比较操作符时,是test命令来解释存放在变量中的整数值,而不是shell。 命令格式为, test 整数测试表达式
  • 547. 例1: $ x1= ″ 005 ″ $ x2= ″ 10″ $ test ″ $x1 ″ = 5 $ echo $? 1 例2: $ test ″ $x1 ″ -eq 5 $ echo $? 0 例3: $ test ″ $x2 ″ -eq 10 $ echo $? 0
  • 548. 5. test用于文件的测试 test可用于文件各种特性的检查。这些文件的操作符自然是一原操作符,意味着它们要求其后跟随一个自变量。在所有的情况中,这个自变量是一个文件或目录名。常用的文件测试表达式示例如下: 例1: 检查指定的文件是否存在并且可读 test -f /usr/fk/message 例2: 检查指定的文件是否为目录 test -d /usr/src/local/sendmail 例3: 检查指定的出错文件是否为空,如不空则列出该文件的内容 test -s $errfile && {echo ″Errors found:″;\ cat $errfile}
  • 549. 6. 表达式的逻辑运算 在实际应用中常需要将多个表达式用逻辑运算符组合起来,构成比较复杂的条件。逻辑运算符包括: ! : 逻辑非单目运算符,可放置在任何其他test表达式之前,求得表达式运算结果的非值。 -a : 逻辑与运算符,执行两个表达式的逻辑与运算,并且仅当两者都为真时,才返回真值。 -o : 逻辑或运算符,执行两个表达式的逻辑或运算,并只要当两者之一为真时,就返回真值。 逻辑运算符优先级(由高到低) 的排列顺序如下: ( ) ! -a -o
  • 550. 逻辑运算符优先级要比字符串操作符、数字比较操作符、文件操作符的优先级低。 例1: 当指定的文件不可读时为真。 test ! -r /usr/fk/message 例2: 当指定的文件均存在,且message为可读、$mailfile 指定的文件为普通文件时,返回真。 test -r /usr/fk/message -a -f ″$mailfile ″ 例3: 当变量值大于等于0并且小于10时为真。 test ″$count ″ -ge 0 -a ″$count ″ -lt 10 例4: 当变量$a等于0或者$b大于5,并且$c小于等于8时为真。 test \(″$a″ -eq 0 -o ″$b″ -gt 5 \)-a ″$c″ -le 8
  • 551. 9.6.2 if结构 1. if的简单结构 格式为, if command then command command ... fi
  • 552. 2. if的完整结构 格式为, if command then command command ... else command command ... fi
  • 553. 3. if的连用结构 格式1 if command then commands else if command then commands else … if command then commands fi ... fi fi
  • 554. 格式2 if command then commands elif command then commands elif … elif commands then commands else commands fi
  • 555. 9.6.3 case结构 格式为, case value in pattern1) command ... command;; pattern2) command ... command;; ... patternn) command ... command;; esac
  • 556. 9.6.4 for结构 格式为, for variable in arg1 arg2 ... argn do command ... command done
  • 557. 9.6.5 while结构 格式为, while command do command ... command done
  • 558. 9.6.6 until结构 格式为, until command do command ... command done
  • 559. 9.6.7 循环体中其他命令 1. break命令 格式为, break或break n break是shell的内部命令,用于在循环体中根据命令运行的返回条件,直接终止循环体内命令的执行。当执行break命令时,控制流从循环体中转移到done之后的第一条命令上。当执行break n命令时,则终止最内层的n个循环的执行。 2. continue 命令 格式为, continue或continue n
  • 560. continue是shell的内部命令,用于在循环体中根据命令运行的返回条件,直接进入下一次循环命令的执行。当执行continue命令时,控制流直接转到本循环体中第一条命令上。当执行continue n命令时,则跳过最里层的 n次循环体的执行,即开始第n个(从内向外数) 循环的下一个循环过程。 3. 循环中的输入输出改向 对整个循环命令也可实施shell命令的输入输出改向。循环输入的改向将作用于循环体中从标准输入读数据的所有命令;而循环输出改向将作用于循环体中向标准输出写数据的所有命令。在循环体内也可以进行输入输出改向,且这种改向独立于整个循环体命令的输入输出改向。
  • 561. 例: while test ″ $count ″ -lt 20 do ... echo ″ error: $count ″ ... echo ″ right: $count ″ >/dev/tty ... done 2 >error.out
  • 562. 4. 循环体与管道 循环命令也能通过管道与其他的shell命令联接在一起使用。一个命令的输出通过管道可以作为循环命令的输入,而整个循环命令的输出也可以通过管道作为另一个命令的输入。 例: $for i in a b c d >do >echo $i >done|wc -l 4
  • 563. 9.6.8 函数的定义和使用 函数实际上是由若干shell命令组成,因此它与shell的命令文件形式上是相似的。不同的只是shell函数常驻于内存之中。它们不再是一个单独的进程,而是成了shell的一部分。 格式为, Function Name(){ command … command }
  • 564. 函数仅存在于定义它的shell环境中,不能把它们传递给子shell。函数是在当前shell中被执行的,在函数体中变量值和当前工作目录的改变,将影响当前shell的运行环境。函数一旦定义就被存入内存,shell执行函数时不需要在磁盘中进行查找,所以执行速度要比把函数中的命令放入到一个文件中的执行要快。使用函数时,命令行中列在函数名后的自变量传递给函数体中的位置参数。函数执行返回时也有一个出口状态。函数体内执行exit命令将结束函数的执行,同时也结束调用函数的shell程序的运行。而return命令用于结束函数的执行,如省略return时,则以最后一条命令的出口状态作为函数的出口状态。
  • 565. 例: # The test codes for function definition GetYesOrNo() { while echo ″ $*(Y/N)? \c ″ > &2 do read reply RestData case ″ $reply ″ in [yY]) return 0 ;; [nN])return 1 ;; *)echo ″ Please enter Y or N ! ″ >&2 ;; esac done 执行$ GetYesOrNo ″ Do you wish to continue ″ || exit 显示Do you wish to continue(Y/ N)?
  • 566. 9.7 shell的运行环境 9.7.1 局部变量 当用户注册之后,用户就拥有了注册shell的运行环境,其运行环境主要由shell变量值决定。注册shell在接受到用户输入的命令(非内部命令)后,通常派生出一个子shell,由此子shell负责解释执行该命令。子shell有自己的运行环境和局部变量,局部变量仅在特定的环境下才能使用。shell的运行环境是可以改变的,但子shell不能存取由父shell设置的局部变量,也不能改变父shell的变量值。
  • 567. 例1: $ cat var-test echo :$x: $ x=100 $ var-test :: 例2: $ cat var-test2 x=60 echo :$x: $ x=10 $ var-test2 :60: $ echo $x 10
  • 568. 9.7.2 全局变量 全局变量是一种特殊的变量,可以被任何运行的子shell来引用。全局变量通过export命令来定义,格式如下: export variables 其中 variables 是定义全局变量的变量表名。 一旦变量被定义为全局变量,则对于以后的所有子shell来说这些都是全局变量。子shell中无法改变全局变量的值。若在子shell中改变全局变量的值,实际是对全局变量的副本进行更改,不影响全局变量值。子shell中局部变量的使用优先于全局变量。
  • 569. 例: $ export g-var $ g-var=″GLOBAL″ $ cat test-var export g-var l-var g-var=″sub-shell:g-var″ l-var=″sub-shell:l-var″ echo $g-var $l-var $ test-var sub-shell:g-var sub-shell:l-var $ echo $g-var :$l-var: GLOBAL :: $
  • 570. 9.7.3 局部变量和全局变量作用域 任何没有用export命令定义过的变量是局部变量,子shell不能存取父shell的局部变量。子shell中可以存取和修改父shell的全局变量,但这种修改对于父shell全局变量没有任何影响。在子shell中用export命令定义的全局变量和对此变量的修改对父shell变量没有影响。全局变量保持它的全局性,不仅能直接传递给它的子shell,而且子shell还能将它传递给子shell的子shell。在对变量赋值之前和之后的任何时候可以将该变量转换成全局变量。
  • 571. 9.7.4 程序调试 shell提供了多种工具以便在调试shell程序时使用,这些工具允许观察一个shell程序的执行,还允许观察一个程序在不做任何实际处理的情况下是如何被“执行”的。提供的测试方式有: 1. shell程序的详细跟踪 shell提供的详细跟踪特性允许用户观察一个shell程序的读入和执行,如果在读入命令行时发现语法错误,则终止程序的执行。命令行被读入后,shell按读入时的形式在标准错误输出中显示该命令行,然后执行命令行。详细跟踪shell程序的执行有两种方式:整个程序的详细跟踪和局部程序的详细跟踪。
  • 572. 整个程序的跟踪执行格式: sh -v 文件名用来实现对整个文件的脚本进行跟踪。 局部程序的跟踪执行格式:set -v——设置跟踪标志 set +v——关闭跟踪标志用来实现对文件中的部分脚本进行跟踪。
  • 573. 例: $ cat traced date echo $PATH|wc -c $ traced 1998年 11月 05日 星期四 17时 29分 59秒 CST 45 $ sh -v traced date 1998年 11月 05日 星期四 17时 30分 08秒 CST echo $PATH|wc -c 45
  • 574. 2. shell程序的跟踪执行 此功能允许用户观察一个shell程序的执行,它使命令行在执行前完成所有替换之后,在标准错误输出中显示每一个被替换后的命令行,并且在行前加上前缀符号“+”(但变量赋值语句不加“+”符号),然后执行命令。对shell程序的跟踪执行也有两种方式:整个程序的跟踪执行和局部程序的跟踪执行。 整个程序的跟踪执行格式为, sh -x 文件名 用来实现对整个文件脚本的跟踪执行。 局部程序的跟踪执行格式为, set -x——设置跟踪标志 set +x——关闭跟踪标志
  • 575. 用来实现对文件中部分脚本的跟踪执行。 例: $ cat traced date echo $PATH|wc -c $ sh -x traced +date 1998年 11月 05日 星期四 17时 30分 08秒 CST +echo /bin:/usr/bin:/usr/fk/bin /bin:/usr/bin:/usr/fk/bin +wc -c 25
  • 576. 3. 详细跟踪与跟踪执行的组合 整个程序的跟踪执行格式为, sh -vx 文件名 局部程序的跟踪执行格式为, set -vx——设置跟踪标志 set +vx——关闭跟踪标志 详细跟踪与跟踪执行的区别在于在执行命令行之前,详细跟踪打印出命令行的原始内容,而跟踪执行却打印出经过替换后的命令行内容,循环结构和管道线在两种跟踪方式中是根本不同的。由于shell对这些结构只读取一次,因此,详细跟踪方式也仅显示它们一次。但这类结构的命令行可能要被重复执行多次,所以,跟踪执行方式就可能将同样的命令行显示一次以上。
  • 577. 4. 非执行跟踪 shell的非执行任选项提供的功能允许用户观察一个shell程序,而程序中的命令行不被执行。非执行通常与详细跟踪结合使用,查看在不实际执行一个shell程序时,程序是如何被“执行”的。其格式为, sh -n 文件名 或 set -n
  • 578. 5. 未置变量退出跟踪 shell的未置变量退出特性允许对所有的变量进行检查,如果引用了一个未赋值的变量就终止shell程序执行。shell通常允许未置变量的使用,在此种情况下,变量的值为空。但如果设置了未置变量退出的任选项,则一旦使用了未置的变量就显示出错信息,并终止程序的运行。其格式为, sh -u 文件名 或 set -u——设置标志 set +u——清除标志
  • 579. 6. 立即退出跟踪 shell的立即退出特性允许在程序内的任何命令以非零状态退出时,立即终止程序的运行。其格式为, sh -e 文件名 或 set -e——设置标志 set +e——清除标志
  • 580. 9.7.5 shell程序的应用 1. shell程序的定义 若一个文件包含了一串简单命令串时,称为命令文件;若一个文件包含了一组更为复杂的命令组合(常常使用了shell的条件命令、控制结构和其他高级特性)时,就称之为shell程序(或称shell过程)。通常情况下,两者的称呼并没有明确的区别。 在shell程序设计语言里的基本操作是Linux系统命令,它是Linux系统中最有生气的部分,而且对于Linux系统的使用极为重要。
  • 581. 2. 何时使用shell程序设计语言 当一个问题的解决方法需要使用多个Linux系统的标准命令时,可使用shell命令文件。如果处理的问题比较复杂,可以使用shell程序设计语言,即在命令文件中定义各种参数和变量,使用shell的条件命令、控制结构和其他高级特性。
  • 582. 9.8 shell应用实例 下面这段程序取自/etc/rc.d/rc.sysinit文件中的一部分,/etc/rc.d/rc.sysinit文件是Linux系统启动过程中需要执行的shell程序。这段程序的功能主要是配置网络环境、检查文件系统和加载应用模块。要注意,在shell程序中注释语句是以#开头,但以#!开头的语句并不是注释语句。如果想执行该程序,可以用一般用户登录系统后,直接执行/etc/rc.d/rc.sysinit。
  • 583. # 第一条语句先指定本shell程序采用哪个shell执行。 #! /bin/sh # 以#开始的语句是注释行。 # /etc/rc.d/rc.sysinit - run once at boot time # # Taken in part from Miquel van Smoorenburg′s bcheckrc. # # 下面语句是定义变量PATH,并把PATH变量声明为全局变量。 # Set the path PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH
  • 584. # 下面命令读取配置数据,这里用到一个简单的IF语句。 # 判断/etc/sysconfig/network文件存在否,如果该文件存在,就执行它。 # 否则,给NETWORKING变量赋值,给HOSTNAME变量赋值。 # Read in config data. if [-f /etc/sysconfig/network]; then . /etc/sysconfig/network else NETWORKING=no HOSTNAME=localhost fi
  • 585. # 下面语句的功能是启用交换,执行shell命令swapon。 # Start up swapping. echo ″Activating swap partitions″ swapon \|a # 以下语句设置主机名。 # 下面语句引用hostname变量,执行hostname命令。 # Set the hostname. hostname ${HOSTNAME} echo hostname: `hostname`
  • 586. # 下面语句设置NIS域名,其中引用$NISDOMAIN变量,执行shell命令domainname。 # Set the NIS domain name if [-n ″$NISDOMAIN″]; then domainname $NISDOMAIN else domainname ″″ fi # 下面是一段简单的if语句,判断/fsckoptions文件是否存在, # 并定义fsckoptions 变量。 if [-f /fsckoptions]; then fsckoptions=`cat /fsckoptions` else fsckoptions=′′ fi
  • 587. # 下面是一段简单的if语句,判断/fastboot文件是否不存在。 # 其中,引用fsckoptions 变量,执行shell语句fsck。 # 并引用系统变量$?,定义变量rc,获取上一个shell语句的执行结果。 if [! -f /fastboot]; then echo ″Checking root filesystems.″ fsck -V -a $fsckoptions / rc=$? # 以下这段语句是检查文件系统的执行结果, # 如果$rc 大于1,说明文件系统有严重问题,并显示信息。 # 其中,给环境变量PS1赋值,执行shell命令sulogin, # 执行shell命令umount a,执行shell命令reboot。 # A return of 2 or higher means there were serious problems. if [$rc -gt 1]; then echo echo echo ″*** An error occurred during the file system check.″ echo ″*** Dropping you to a shell; the system will reboot″ echo ″*** when you leave the shell.″
  • 588. PS1=″(Repair filesystem) #″; export PS1 sulogin echo ″Unmounting file systems″ umount a mount -n -o remount, ro/ echo ″Automatic reboot in progress.″ reboot # 下面语句是嵌套的复合条件if语句,执行shell命令quotacheck elif [″$rc″=″1″ -a -x/sbin/quotacheck]; then echo ″Checking root filesystem quotas″ /sbin/quotacheck -v/ fi fi
  • 589. # 下面语句对根系统实行磁盘空间限定,执行shell命令quotaon。 if [-x/sbin/quotaon]; then echo ″Turning on user and group quotas for root filesystem″ /sbin/quotaon/ fi # 下面命令是设置PNP,首先检查参数,执行shell命令mount。 # 在if语句中采用输出重定向,定义变量PNP。 # check for arguments mount -t proc/proc/proc if grep -i nopnp/proc/cmdline>/dev/null; then PNP= else PNP=yes fi
  • 590. # 以下语句设置PNP, 先使用一个简单if语句,复合条件,并引用变量PNP。 # 执行shell命令isapnp。 # set up PNP if [-x /sbin/isapnp -a -f /etc/isapnp.conf]; then if [-n ″$PNP″]; then echo ″Setting up ISA PNP devices″ /sbin/isapnp/etc/isapnp.conf else echo ″Skipping ISA PNP configuration at users request″ fi fi
  • 591. # 下面命令重新mount根文件系统,执行shell命令mount # 如果/etc/HOSTNAME不存在,则把${HOSTNAME}变量的值输出到/etc/HOSTNAME文件中。 # Remount the root filesystem read-write. echo ″Remounting root filesystem in read-write mode.″ mount -n -o remount,rw / if [! -f /etc/HOSTNAME]; then echo ${HOSTNAME} > /etc/HOSTNAME fi # 清空/ etc/mtab文件 # clear mtab >/etc/mtab
  • 592. # 执行shell命令,把/和/proc文件系统加载上。 # Enter root and /proc into mtab. mount -f / mount -f /proc # 如果/proc/ksyms文件存在, 定义变量USEMODULES为y。 if [-f /proc/ksyms]; then USEMODULES=y else USEMODULES= fi
  • 593. # 下面命令是获取要执行的模块。 # 先执行shell命令rm删除文件, 引用变量USEMODULES, # 并用set给位置变量强制赋值,引用系统变量$#,引用位置变量$1, # 在if语句中使用管道命令,使用输出重定向。 # Get the modules ready to go -- we use awk here as cut is in /usr/bin rm -f /lib/modules/preferred if [-n $USEMODULES]; then set `cat /proc/cmdline` while [$# -gt 0]; do if echo $1|grep ′^BOOT-IMAGE=′ > /dev/null ; then # # # 中间略去部分语句 # # 下面语句初始化串口, 执行shell命令rc.serial。 # Initialize the serial ports. if [-f /etc/rc.d/rc.serial]; then . /etc/rc.d/rc.serial fi
  • 594. # 下面语句加载模块, 执行shell命令rc.modules。 # Load modules (for backward compatibility with VARs) if [-f /etc/rc.d/rc.modules]; then /etc/rc.d/rc.modules fi # 下面语句是检查SCSI磁带设备。 # If a SCSI tape has been detected, load the st module unconditionally # since many SCSI tapes don′t deal well with st being loaded and unloaded # 这里用到带复合条件的if语句,并使用管道命令和重定向命令。 if [-f /proc/scsi/scsi] && cat /proc/scsi/scsi|grep -q ′Type:Sequential-Access′ 2>/dev/null ; then if cat /proc/devices|grep -qv ′ 9 st′ ; then if [-n ″$USEMODULES″] ; then # Try to load the module. If it fails, ignore it... modprobe st 2>/dev/null fi fi fi
  • 595. # 下面执行shell命令dmesg,显示系统配置信息, # 并把输出结果重定向到/var/log/dmesg中。 # Now that we have all of our basic modules loaded and the kernel going, # let′s dump the syslog ring somewhere so we can find it later dmesg > /var/log/dmesg # 执行shell命令random start。 # Feed entropy into the entropy pool /etc/rc.d/init.d/random start
  • 596. 9.9 小结 本章主要介绍了什么是shell、shell变量、shell命令以及shell 语言控制结构,并着重讲述了如何使用shell语言编写shell程序并调试运行。大家要充分理解shell变量,通过编写shell程序并运行,来理解shell程序在整个Linux系统所起的巨大作用。
  • 597. 习题 9-1 什么是shell?什么是重定向?什么是管道? 9-2 shell变量怎么用?常用的预定义变量和环境变量都有哪些?常用的位置变量和系统自动赋值有哪些? 9-3 往你的主目录下随便拷贝5个文件,用mv命令将这些文件名都变成大写,现在请你编个shell程序,将这些文件名都变成小写。 9-4 编写一个shell程序,它能够将指定目录及其子目录中的包含字符串root的文本文件找出来。
  • 598. 第9章 shell编程9.1 shell概述 9.2 shell的基本功能 9.3 shell启动及其命令 9.4 shell命令的集成 9.5 shell变量 9.6 shell的控制结构 9.7 shell的运行环境 9.8 shell应用实例 9.9 小结 习题
  • 599. shell是一种命令语言,同时又是一种程序设计语言。shell的语言处理能力,使得用户能够方便地定义各种变量、参数,并使用各种控制语句编写复杂的命令程序完成多种工作。本章介绍shell、shell程序设计语言、shell的运行环境及shell程序的调试。
  • 600. 9.1 shell概述 9.1.1 什么是shell shell是一种命令解释程序(命令解释器),shell解释用户输入的命令行,提交系统内核处理,并将结果返回给用户。与Linux命令一样都是实用程序,但两者又有区别。一旦用户注册到系统后,shell就被系统装入内存,并一直运行到用户退出系统之止;而一般命令仅当被调用时,才由系统装入内存执行。 shell本身也是一种可编程的程序设计语言。用shell写的程序(shell脚本)相当于dos/windows下的批处理文件,它可以简单到只有一条命令,也可以复杂到包括大量循环、条件语句、数学运算、控制结构,也可以是介于两者之间的程序。
  • 601. 9.1.2 shell程序语言的特点 shell允许通过编程来完成复杂的功能处理,但其作为语言与高级语言相比较具有不同的特点: (1) shell是解释性的,多数高级语言是编译性的; (2) shell语言与高级语言处理的对象不同; (3) shell与系统有密切的关系; (4) shell易编写、调试、灵活性较强,但速度低; (5) shell作为命令级语言,命令组合功能很强。
  • 602. 9.1.3 shell的版本 shell有两种主要语法类型: Bourne shell和C shell,彼此不兼容。Bourne shell家族:sh ksh bash psh zsh;C shell家族:csh tcsh。 其中bash和 zsh在不同程度上支持 csh 的语法。 这里,我们再着重介绍一下bash的特点: (1) 自动补全功能 假设要输入的命令很长,或者命令后面要给的文件名很长。这个时候只要按一个Tab键,bash就会在可能的命令或文件名里面找寻匹配的命令,找到的话就会自动帮你补齐。
  • 603. (2) 命令行编辑程序 bash的命令行编辑是在提示符下,可对未执行的命令字符任意地修改。 (3) 命令历史(command history) 所谓的命令历史就是把曾经输入过的命令记录起来,方便日后的查询与使用。只要按向上键就可以调出前一个命令,再按一次向上键就可以调出更前一个命令,依此类推,用向下键可以回到下个命令,所以用上、下键就可以选择以前输入过的命令。
  • 604. 9.2 shell的基本功能 9.2.1 程序的运行 当用户输入一行命令后,shell负责解释、分析输入的内容,并且决定做什么,同时替系统内核删除命令行中不必要的信息。命令是一个可执行的Linux命令、程序、工具或shell脚本。 例1: $ls -l file1 file2 file3 例2: $echo ′Welcome to Tsinghua University.′ 例3: $echo Welcome to Tsinghua University. 注意: 例2和例3的结果是完全一样的。
  • 605. 9.2.2 使用保留字和元字符 shell有一些具有特殊意义的字(保留字) ,如在shell脚本中,像do、done、for、while等保留字控制循环操作,if、then、else等保留字进行条件控制。保留字随shell的不同而不同。 在Linux系统里,有一组特殊意义字符,这就是所谓的元字符(通配符)。 现在列出一些常用的通配符的意义,供参考。 .. 上一层目录,与cd命令配合用得比较多 . 目前工作的目录 * 任意长度的字符 ? 长度为一个的任意字符
  • 606. [..] 括号内的一个字符 \m 等于某个通配符,如*、?等 [a-z]* 小写字母开头的所有字符串 \ 转义符号,用以解除特殊字符的特殊意义 ~ 用户目录 ; 分隔符,当命令行有多个命令时,做分隔用 $ BourneShell的提示符,同时也作为shell语言的位置变量参数 # 做注释用 | 建立一个管道,使一命令的输出作为另一个命令的输入 & 将命令以后台方式执行
  • 607. > 将命令的输出重导入文件中 < 将命令的输入流指定为由文件中加载,和>相反 >> 将命令的输出加在一个已经存在的文件后面 {..} 括号内的一个字符串 例: $ls -x t*显示当前目录下以t打头的所有文件。
  • 608. 9.2.3 变量、文件名的替换 1. 变量的替换 shell允许对变量赋值。shell一旦在命令行中发现$变量名时,将在$变量名的位置上用以前赋给该变量的值替代$变量名。 例: $myhome=/usr/app1 $echo $myhome /usr/app1 $ls -x $myhome file1 file2 file3 file4
  • 609. 2. 文件名的替换 shell在命令行中将文件名进行替换。事实上,shell在确定要执行的程序名和它的自变量之前,要对命令行扫描,找出元字符进行相应的文件名的替换。 例: $ls -x file1 file2 file3 file4 $echo* file1 file2 file3 file4
  • 610. 9.2.4 输入输出重定向(改向) shell处理命令行的输入输出重定向,它扫描命令行中特殊改向字符“>”、“<”、“>>”、“<<”,将输入或输出改向到指定的文件中。 例: $echo “Please call me:62781849” > msg $cat msg Please call me:62781849 注意: 就程序或命令本身而言,它并不知道其标准输出已被改向,只是简单地按照自身的方式向标准输出输送信息。
  • 611. 正如shell扫描命令行查找重定向字符一样,它也查找管道字符“|”。对于所发现的每个管道字符,它将管道字符前面的命令的标准输出连接到管道字符后面的命令的标准输入中,然后启动两个程序的执行。 例: $w|wc -l(假设有8个用户上机) 8
  • 612. 9.2.5 运行环境的控制 当用户登录到Linux系统中,系统启动一个交互式的shell命令解释器(称为注册shell)。该shell为此用户创建工作环境。shell提供了一定的命令,允许用户对自己运行的环境进行控制,即对运行环境实现客户化。用户的运行环境包括:主目录、终端类型、输入命令提示符、查找命令的路径名、以及其他全局变量等。例如,Bourne again Shell、Bourne Shell、Korn Shell和C Shell的环境文件分别为.bash-profile、.profile、.kshrc和.cshrc。
  • 613. 9.2.6 支持shell的编程 shell除了具有命令解释器的功能外,它本身就是一种程序设计语言,这种语言也由shell解释执行的。用户可以在文件中编写一组shell命令,该文件称为shell脚本或shell程序。通过把命令、变量赋值及条件控制语句结合起来,用户就获得了一个强大的编程工具。需要说明的是,在Linux系统本身就存在大量的shell程序,用于各种管理和应用。
  • 614. 9.3 shell启动及其命令 9.3.1 shell的启动 1.系统在用户登录时启动shell 在Linux系统引导过程中,首先启动init进程以查询终端的各个端口及其特性,当发现活动的终端时,调用getty进程。接着getty进程在接受用户名和口令后,调用login进程。login进程负责验证用户身份,验证后把控制权交给shell程序。shell根据环境文件建立系统范围内的工作环境和该用户自己的工作环境,最后显示命令提示符(#、$、%)。 在/etc/passwd文件中指定要启动的shell,如下所示:
  • 615. root:x:0:0:root:/root:/bin/bash john:x:201:Certer′starf:/home:/bin/sh 2. 命令行状态下的交互shell启动 在系统中可能有多种版本的shell存在,可通过相应的命令来启动,如: $bsh $ksh $sh 3. 执行用户命令时启动shell(子shell) 由系统生成新的子shell来执行该命令。
  • 616. 9.3.2 命令的查询 环境变量PATH的构成决定了寻找shell命令和其他程序的途径,是影响shell程序效率的主要因素之一。PATH变量设置要考虑以下几点:在PATH变量中,命令使用得多的程序目录应放在前面,极少用目录不设在PATH变量中。在shell程序内用得较多的程序目录应加在变量PATH中。并且PATH应尽可能地短,不要出现重复的目录。还要尽量避免查询大目录,如需设置,将其路径放在PATH路径的最后位置。 例: PATH=/bin:/usr/bin:/etc:.
  • 617. 9.3.3 shell常用的命令 Linux系统通常提供了许多命令以方便用户与系统的交互对话。这些命令的选项较多,并且可利用命令的集成(如输入输出改道、管道机制)及程序设计功能组合成许多命令。 Linux有丰富的shell命令,大致划分为以下几类:目录操作与管理、文件操作与管理命令、系统管理与维护、用户管理与维护、系统状态、进程管理、通讯命令、其他命令。例如, awk cat chmod chown cp cron date df diff du echo expr file find grep init kill ln login ls mail make man mkdir mv nohup pg ps pwd read rm wc
  • 618. 通常情况下,在用户输入一个命令(非内部命令)时,注册shell首先通过查询路径查找该命令,然后生成出一个副本(称为该shell的子shell),由子shell来负责解释执行这个命令。在命令执行过程中,注册shell(父shell)等待子shell的执行而进入睡眠态,一旦子shell执行完毕,子shell将唤醒注册shell(父shell),而自己的生命周期到此结束。
  • 619. 9.3.4 shell的内部命令 内部命令构造在shell的内部。内部命令比非内部命令的执行速度要快。因此,编写shell程序时应尽量地使用shell的内部命令。shell常用的内部命令有: # 注释命令,#后面的内容作为注释信息。 : 空命令,通常放在一行的最左边,实际不做任何命令,只返回出口代码0。 其他命令有:cd,eval,set,unset,exec,exit,if,else,for,case,while,until,continue,break等。
  • 620. 9.4 shell命令的集成 9.4.1 元字符和文件名生成 1. UNIX元字符(通配符)的定义 * 匹配任何字符串,包括空字符串; ? 匹配任何单个字符; [.,-,!] 按照范围、列表或不匹配等形式匹配指定的字符; \ 转意符,使元字符失去其特殊的含义。 例: [a-d,x,y] 匹配字符a、b、c、d、x、y; z* 匹配以字符z开始的任何字符串;
  • 621. x?y 匹配以x开始、以y结束、中间为任何单个字符的字符串; [!Z] 匹配不为Z的单个字符。 2. 元字符作为文件扩展名的使用 例: [a-f]* 匹配字符a到字符f开头的文件名,如abc,d2,e3.c,f.dat; *z 匹配以字符z结尾的任何字符串,如win.z,core.zz,a-c-5z; rc?.d 匹配以rc开始、以.d结束、中间为任何单个字符的文件名,如rc0.d,rc2.d,rcS.d; *[!o] 匹配不以o结尾的文件名。
  • 622. 9.4.2 管道和命令表 在shell中有两种结构类型:管道线和命令表。当shell检测到一个管道操作符时,就建立一个系统管道文件,这是一个先进先出的数据结构,它允许在同一时刻对管道线上的命令或程序进行读和写,即允许两个无关的命令通过管道连接交换信息。 1. 管道的概念 管道:是一个命令的标准输出与另一个命令的标准输入之间的连接,不经过任何中间文件; 管道线:是由管道操作符分隔的一个命令序列,最简单的管道线是一个简单命令; 管道操作符:用符号“|”表示。
  • 623. 例: w|wc -l ps aux|grep ftp 2. 命令表的概念 命令表:一串管道线构成了一个命令表,最简单的命令表是一个管道线,一个命令表送回的值是该命令表中最后一个管道线的出口状态。 管道线分隔符:分隔命令表元素,确定管道线执行的条件。各分隔符含义如下: ; 表示按顺序执行管道线; && 表示根据条件(true),执行其后面的管道线; ‖ 表示根据条件(false),执行其后面的管道线;
  • 624. & 表示前面的管道线在后台(异步)执行。 例1: 四个管道线构成一个命令表 ls -l /tmp /root w|wc -l ps 例2: 与例1等价 ls -l /tmp /root ;w|wc -l ;ps 例3: sys-account &
  • 625. 9.4.3 命令组合 命令组合有两种形式:{命令表}和(命令表),前者只在本shell中执行,不产生新的子进程;后者要产生新的子进程来执行命令表。 例1: { cd mydoc; rm junk;} 该命令表只能在当前shell下执行,先进入目录mydoc,然后执行rm命令,执行完毕后,当前目录已改变为mydoc。 例2: (cd mydoc; rm junk;) 当前shell要生成一个子shell进程,由该子shell来执行命令表。子shell完成操作后,自然消亡,而其父shell进程的当前路径并没有变化。
  • 626. 9.4.4 命令替换 当一个字符串被括在反撇号“ ` ”中时,该字符串将作为命令被shell解释执行,即用命令的执行结果替换这个字符串本身。要注意反撇号与单引号的区别。 例1:$ now=′date′ $ echo $now date $ now=`date` $ echo $now 1998年 10月 28日 星期三 17时 51分 56秒 CST 例2:$ count=10 $ count=`expr $count+1` $ echo $count 11
  • 627. 9.4.5 输入、输出重定向 1. 使用标准改向符进行重定向(改向) < 输入改向 << 追加输入改向 > 输出改向 >> 追加输出改向 2. 使用标准文件描述字进行重定向(改向) 在Linux系统中,定义了用于输入、输出的标准文件,其文件描述字0为进程的标准输入、文件描述字1为标准输出、文件描述字2为标准错误输出。 3. 标准错误输出的改向(>、>>) 格式为:
  • 628. command 2 >file command 2 >>file 例1: 将myfile1作为sort的输入。 sort myfile2 例3: 将ls \|l的输出追加到myfile3文件中。 ls -l>>myfile3 例4:将错误输出改向到err-file文件。 $myprog 2>err-file 例5:将标准输出和错误输出改向out文件。 $myprog >out 2>>out $myprog >out 2>>&1
  • 629. 9.5 shell变量 9.5.1 shell变量描述 shell实际上是基于字符串的程序设计语言,但也有变量。shell变量能够而且只能存储正文字符串,即它只有一种类型的变量即串变量。但从赋值的形式上看,则可以分成四种类型的变量或变量形式。变量的名字必须以字母或下划线开头,可以包括字母、数字和下划线。 9.5.2 用户自定义变量 用户自定义变量语法格式:name=string,赋值号“=”两边不允许有空白符。 例:
  • 630. nodehost=beijing.UUCP path=/bin:/usr/bin:/etc/bin count=10 允许多个赋值操作,按从右到左的顺序进行。 例: $A=$BB=abcC=″OK″ $ echo $A $B $C abc abc OK 当引用一个未设置的变量时,其隐含值为空。 例: $ echo ″$mail is path of mailbox″ is path of mailbox
  • 631. 如果用双引号“”将值括起来,则括起来的字符串允许出现空格、制表符和换行符等特殊字符,而且允许有变量替换。 例1:$ MAIL=/var/mail/fk $ var=″$MAIL is path of mailbox″ $ echo $var /var/mail/fk is path of mailbox 例2: $ str=″This is \n a book″ $ echo $str This is a book
  • 632. 如果用单引号‘’将值括起来,则括起来的字符串允许出现空格、制表符和换行符的特殊字符,但不允许有变量替换。 例3: $ BOOK=″English book″ $ MSG=′$BOOK′ $ echo $MSG $BOOK 例4: $ msg=′ Today is Sunday′ $ echo $msg Today is Sunday
  • 633. 引用变量的值时,可以用花括号{}将变量名称括起来,使变量名称与它的后续字符分隔开,如果紧跟在变量名称后面的字符是字母、数字或下划线时,必须要使用花括号。 例5: $ str=′This is a string′ $ echo ″${str}ent test of variables″ This is a stringent test of variables $ echo ″$strent test of variables″ test of variables
  • 634. 可将变量设置为只读形式,格式为,readonly 变量名1 变量名2 例6: $ ux=UNIX.SUN $ readonly ux $ ux=UNIX.SCO ux: is read only 查看只读形式的变量,格式为readonly 例7: $ readonly readonly ux
  • 635. 9.5.3 位置变量 位置变量顾名思义是与变量所在位置有关的变量,这是一种特殊的变量。当一个shell过程被调用时,shell隐含地为它建立一系列的位置变量。这种位置变量是系统预定义好的,可以直接引用。如命令行的shell过程名本身被指定为位置变量$0,第一个命令参数为$1,……,第九个命令参数为$9。 例: ls / /bin /etc /usr/bin /dev $0 $1 $2 $3 $4 $5
  • 636. 1. 内部命令shift 的作用 当位置变量个数超出9时,就不能直接引用位置大于9的位置变量了,必须用shift命令存取。每执行一次shift命令,删除$1位置变量,并使其他的所有位置变量向左移动一个位置。 例: $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 myprog a b c d e f g h i j shift b c d e f g h i j shift c d e f g h i j shift d e f g h i j
  • 637. 2. 用set命令进行强制性赋值 位置变量可以使用set命令进行强制性赋值。 例: set Sun Mon Tue Wed Thu Fri Sat 结果$1 $2 $3 $4 $5 $6 $7 注意: $0是不能用这种方法赋值的。
  • 638. 9.5.4 环境变量 shell执行环境由一系列环境变量组成,这些变量是由shell维护和管理的。所有这些变量都可被用户重新设置,变量名由大写字母或数字组成。 CDPATH 执行cd命令时使用的搜索路径; HOME 用户的home目录; PATH 寻找命令或可执行文件的搜索路径; PS1 主命令提示符,默认为“$”; PS2 从命令提示符,默认为“>”; TERM 使用的终端类型。
  • 639. 9.5.5 预定义的特殊变量 在shell中有一组特殊的变量,其变量名和变量值只有shell本身才可以设置。 “$#” 记录传递给shell的自变量个数。 例1: myprog a b c 则 $#的值为3 例2: if test $# -lt 2 then echo ″ two or more args required ″ exit fi
  • 640. “$?”取最近一次命令执行后的退出状态:执行成功返回码为0,执行失败返回码为1。 例: $test -r my-file(假设my-file文件不可读) $echo$? 1 “$$”记录当前shell的进程号。
  • 641. 9.5.6 变量替换 shell在遇到未设置的变量时,将其值作为空串处理。而在实际应用中,对于未设置的变量,用户可以根据需要采用不同的处理方式,这可通过变量替换来实现。变量替换提供了三种功能:允许替换未设置变量的隐含值;允许对未设置变量赋值;在访问未设置变量时,提示出错信息。格式为, ${var:-word} 例1: 假设$PARM未设置 $echo ″ The value of PARM is ${PARM:-undefined}″ The value of PARM is undefined $echo $PARM -
  • 642. 例2:假设$PARM未设置 $arg=${PARM:- ″ not defined ″} (注意: 双引号) $echo ′ $arg : ′$arg $arg : not defined 例3:对未设置变量赋值 $cat use.d sel=$1 :${sel∶=main}(注意: 此处的“:” 为空命令) echo ″ Your selection is $sel ″ $use.d programming Your selection is programming
  • 643. 注意: 变量替换的这种形式不允许使用位置变量,若要使用位置变量,则必须先将位置变量赋值给一中间变量,然后再对中间变量进行这种形式的替换。 例4:将例3中的空命令用中间变量替换。 $cat use.d sel=$1 my-sel=${sel∶=main} echo ″ Your selection is $my-sel ″ $use.d programming Your selection is programming
  • 644. 例5: 测试环境变量TERM是否设置。 $cat check.env : ${TERM:? ″ the TERM varible should be set ″ } 注意: 出错信息以一行长为限,且输出到标准错误输出上。
  • 645. 9.5.7 特殊字符的引用 在shell中所使用的许多特殊符号也可为其他目的所使用,因此当不需要引用这些字符的特殊含义时,就必须进行删除。消除特殊字符的含义有3种常用的方法,分别是转义符、单引号和双引号。 1. 转义符(\)的引用 使用转义符消除单个字符的特殊含义,即将紧跟在转义符后面的单个字符按字符本身的实际含义解释。 例:转义符具有续行功能 $ cat back.sh echo ″Enter your name: \\c″ read name echo Hello $name
  • 646. $ back.sh Enter your name: john Hello john 2. 单引号 (‘’)的引用 使用单引号消除被括在单引号中的所有特殊字符的含义,即单引号表示内容照原样不动。 例1: $echo ′type a $* please′ type a $* please 例2: 在指定的目录中,查找名字为 *.zh 或 $.sh文件。 $cat test.sh grep ′*.zh | $.sh′ $1
  • 647. 3. 双引号 (“”)的引用 使用双引号能消除被括在双引号中的大部分特殊字符的含义,不能消除的字符有:$、 ` 、″、 \。 例1:$echo ″ Type a \$*, please ″ Type a $*, please 例2: vdate= ″`date` is the system maintenance time ! ″ 例3: $cat share-file mkdir /tmp/fk chmod 755 /tmp/fk cp ″$@″ /tmp/fk chmod 777 /tmp/fk/*
  • 648. 4. 特殊字符串引用的例外 引用双引号、单引号和转意符都不能消除对echo命令有特殊功能的控制字串的特殊含义。这些控制字串是: \b 退格 \c 显示后不换行 \f 在终端上屏幕的开始处显示 \n 换行 \r 回车 \t 制表符 \v 垂直制表符 \ 反斜杠
  • 649. 9.6 shell的控制结构 9.6.1 条件与test命令 在程序设计语言中,作出决策的结构称为条件。在高级语言中决策的作出是依赖于基本运算的结果;在shell语言中,作出决策所依赖的条件是所执行命令的“出口状态”。 当shell命令或程序执行成功时,它返回一个“零”出口状态(即$?为零);如果执行的命令或程序出错时,则返回一个“非零”的出口状态(即$?不为零)。 除了一般命令的出口状态外,UNIX还提供了两个命令true和false的出口状态。true的出口状态为零;而false的出口状态为非零。shell将true和false命令作为恒真和恒假条件使用。
  • 650. 例: 判断所给出的参数是否为一个目录。 $cat check.dir test -d $1 && echo ″ $1 is a dictory ″ && exit 0 echo ″ $1 is not a dictroy ″ exit 1 在上例中,使用了exit命令。它是一个shell的内部命令,用于终止shell程序的执行。该命令可带一个定义出口状态值的自变量。 例: exit(0): 终止程序的执行,并返回零值; exit(1)或exit(x): 终止程序的执行,并返回非零值; 将命令返回零出口状态称为返回“真值”; 将命令返回非零出口状态称为返回“假值”。
  • 651. 1. test命令 test命令是shell程序设计的条件判断中最常用的测试命令,它有两种等价的格式: test expression或[expression](注意:[ ]中的空格) 其中expression就是要测试的条件。如果test计算expression的结果为真,则返回“零”出口状态,否则返回“非零”出口状态。test命令可用于对字符串、整数及文件进行各类测试。
  • 652. 2. test字符串测试表达式 例1: 两个字符串进行比较 $ user=smith $ test ″$user″= smith $ echo $? 0 $ test ″$user″ = tom $ echo $? 1
  • 653. 例2: 带有空格的字符串比较 $ month=″January ″ $ test ″$month″ = January $ echo $? 1 $ test $month = January $ echo $? 0 注意: shell在处理变量时,遇到有双引号将保留其内容,而省略双引号时,将滤去空格。
  • 654. 例3: 带有空格的字符串比较 $ a=″testing string″ $ test ″$a″ = ″testing string″ $ echo $? 0 $ test $a = ″testing string″ test: unknown operator string shell处理变量 $a 时,将其进行变量替换,然后将结果(testing string)传递给test,而test将string作为操作符来处理,因此出错。
  • 655. 例4: 带有空串(或未设置的字符串比较) $ name= $ test ″$name″ = smith $ echo $? 1 $ test $name = smith test: argument expected shell处理变量$name时,双引号将其括起的内容作为一个“位置持有者”来保留,并把该值传递给test,保证处理的正常执行。
  • 656. 例5: 带有空串的字符串比较 $ blanks=″″ $ test $blanks $ echo $? 1 $ test ″$blanks″ $ echo $? 0 shell处理变量$blanks时,将空格滤去,使其变为空串传递给test;而双引号保留 “位置持有者”的位置,其值为一个空格(空白符),传递给test。
  • 657. 例6: 带有算符的字符串比较 $ symvar=″=″ $ echo ″$symvar″ = $ test -z ″$symvar″ test: argument expected 出错的原因是“=”运算符比“-z”运算符的优先级要高,因此,test 命令期望在等号之后要有一个自变量。为避免上述问题发生,可用下面命令形式替换: $ test x″$symvar″ = x $ echo $? 1
  • 658. 3. 使用test测试字符串时要注意的问题 (1) 向test 传递的各自变量之间必须有空白字符,如果“=”与任一自变量之间没有空白字符就会产生错误。 (2) 在使用变量的值替换的自变量上,用双引号括起来十分必要,以保证test在变量的值为空时也能接收到该自变量,这是一种良好的shell程序设计风格。 (3) 在test命令的测试中,空格和引号是shell程序设计中经常发生错误的焦点,要特别引起注意。 (4) test命令对它的自变量非常讲究,在比较的串中出现运算符时,要考虑到运算符优先级的问题。
  • 659. 4. test命令可用于整数比较 首先要搞清楚整数比较的两个概念: shell并不区分放在shell变量中的值的类型,就变量本身而言,它存放的仅仅是一组字符串,即shell只有一种类型的变量——串变量;当使用整数比较操作符时,是test命令来解释存放在变量中的整数值,而不是shell。 命令格式为, test 整数测试表达式
  • 660. 例1: $ x1= ″ 005 ″ $ x2= ″ 10″ $ test ″ $x1 ″ = 5 $ echo $? 1 例2: $ test ″ $x1 ″ -eq 5 $ echo $? 0 例3: $ test ″ $x2 ″ -eq 10 $ echo $? 0
  • 661. 5. test用于文件的测试 test可用于文件各种特性的检查。这些文件的操作符自然是一原操作符,意味着它们要求其后跟随一个自变量。在所有的情况中,这个自变量是一个文件或目录名。常用的文件测试表达式示例如下: 例1: 检查指定的文件是否存在并且可读 test -f /usr/fk/message 例2: 检查指定的文件是否为目录 test -d /usr/src/local/sendmail 例3: 检查指定的出错文件是否为空,如不空则列出该文件的内容 test -s $errfile && {echo ″Errors found:″;\ cat $errfile}
  • 662. 6. 表达式的逻辑运算 在实际应用中常需要将多个表达式用逻辑运算符组合起来,构成比较复杂的条件。逻辑运算符包括: ! : 逻辑非单目运算符,可放置在任何其他test表达式之前,求得表达式运算结果的非值。 -a : 逻辑与运算符,执行两个表达式的逻辑与运算,并且仅当两者都为真时,才返回真值。 -o : 逻辑或运算符,执行两个表达式的逻辑或运算,并只要当两者之一为真时,就返回真值。 逻辑运算符优先级(由高到低) 的排列顺序如下: ( ) ! -a -o
  • 663. 逻辑运算符优先级要比字符串操作符、数字比较操作符、文件操作符的优先级低。 例1: 当指定的文件不可读时为真。 test ! -r /usr/fk/message 例2: 当指定的文件均存在,且message为可读、$mailfile 指定的文件为普通文件时,返回真。 test -r /usr/fk/message -a -f ″$mailfile ″ 例3: 当变量值大于等于0并且小于10时为真。 test ″$count ″ -ge 0 -a ″$count ″ -lt 10 例4: 当变量$a等于0或者$b大于5,并且$c小于等于8时为真。 test \(″$a″ -eq 0 -o ″$b″ -gt 5 \)-a ″$c″ -le 8
  • 664. 9.6.2 if结构 1. if的简单结构 格式为, if command then command command ... fi
  • 665. 2. if的完整结构 格式为, if command then command command ... else command command ... fi
  • 666. 3. if的连用结构 格式1 if command then commands else if command then commands else … if command then commands fi ... fi fi
  • 667. 格式2 if command then commands elif command then commands elif … elif commands then commands else commands fi
  • 668. 9.6.3 case结构 格式为, case value in pattern1) command ... command;; pattern2) command ... command;; ... patternn) command ... command;; esac
  • 669. 9.6.4 for结构 格式为, for variable in arg1 arg2 ... argn do command ... command done
  • 670. 9.6.5 while结构 格式为, while command do command ... command done
  • 671. 9.6.6 until结构 格式为, until command do command ... command done
  • 672. 9.6.7 循环体中其他命令 1. break命令 格式为, break或break n break是shell的内部命令,用于在循环体中根据命令运行的返回条件,直接终止循环体内命令的执行。当执行break命令时,控制流从循环体中转移到done之后的第一条命令上。当执行break n命令时,则终止最内层的n个循环的执行。 2. continue 命令 格式为, continue或continue n
  • 673. continue是shell的内部命令,用于在循环体中根据命令运行的返回条件,直接进入下一次循环命令的执行。当执行continue命令时,控制流直接转到本循环体中第一条命令上。当执行continue n命令时,则跳过最里层的 n次循环体的执行,即开始第n个(从内向外数) 循环的下一个循环过程。 3. 循环中的输入输出改向 对整个循环命令也可实施shell命令的输入输出改向。循环输入的改向将作用于循环体中从标准输入读数据的所有命令;而循环输出改向将作用于循环体中向标准输出写数据的所有命令。在循环体内也可以进行输入输出改向,且这种改向独立于整个循环体命令的输入输出改向。
  • 674. 例: while test ″ $count ″ -lt 20 do ... echo ″ error: $count ″ ... echo ″ right: $count ″ >/dev/tty ... done 2 >error.out
  • 675. 4. 循环体与管道 循环命令也能通过管道与其他的shell命令联接在一起使用。一个命令的输出通过管道可以作为循环命令的输入,而整个循环命令的输出也可以通过管道作为另一个命令的输入。 例: $for i in a b c d >do >echo $i >done|wc -l 4
  • 676. 9.6.8 函数的定义和使用 函数实际上是由若干shell命令组成,因此它与shell的命令文件形式上是相似的。不同的只是shell函数常驻于内存之中。它们不再是一个单独的进程,而是成了shell的一部分。 格式为, Function Name(){ command … command }
  • 677. 函数仅存在于定义它的shell环境中,不能把它们传递给子shell。函数是在当前shell中被执行的,在函数体中变量值和当前工作目录的改变,将影响当前shell的运行环境。函数一旦定义就被存入内存,shell执行函数时不需要在磁盘中进行查找,所以执行速度要比把函数中的命令放入到一个文件中的执行要快。使用函数时,命令行中列在函数名后的自变量传递给函数体中的位置参数。函数执行返回时也有一个出口状态。函数体内执行exit命令将结束函数的执行,同时也结束调用函数的shell程序的运行。而return命令用于结束函数的执行,如省略return时,则以最后一条命令的出口状态作为函数的出口状态。
  • 678. 例: # The test codes for function definition GetYesOrNo() { while echo ″ $*(Y/N)? \c ″ > &2 do read reply RestData case ″ $reply ″ in [yY]) return 0 ;; [nN])return 1 ;; *)echo ″ Please enter Y or N ! ″ >&2 ;; esac done 执行$ GetYesOrNo ″ Do you wish to continue ″ || exit 显示Do you wish to continue(Y/ N)?
  • 679. 9.7 shell的运行环境 9.7.1 局部变量 当用户注册之后,用户就拥有了注册shell的运行环境,其运行环境主要由shell变量值决定。注册shell在接受到用户输入的命令(非内部命令)后,通常派生出一个子shell,由此子shell负责解释执行该命令。子shell有自己的运行环境和局部变量,局部变量仅在特定的环境下才能使用。shell的运行环境是可以改变的,但子shell不能存取由父shell设置的局部变量,也不能改变父shell的变量值。
  • 680. 例1: $ cat var-test echo :$x: $ x=100 $ var-test :: 例2: $ cat var-test2 x=60 echo :$x: $ x=10 $ var-test2 :60: $ echo $x 10
  • 681. 9.7.2 全局变量 全局变量是一种特殊的变量,可以被任何运行的子shell来引用。全局变量通过export命令来定义,格式如下: export variables 其中 variables 是定义全局变量的变量表名。 一旦变量被定义为全局变量,则对于以后的所有子shell来说这些都是全局变量。子shell中无法改变全局变量的值。若在子shell中改变全局变量的值,实际是对全局变量的副本进行更改,不影响全局变量值。子shell中局部变量的使用优先于全局变量。
  • 682. 例: $ export g-var $ g-var=″GLOBAL″ $ cat test-var export g-var l-var g-var=″sub-shell:g-var″ l-var=″sub-shell:l-var″ echo $g-var $l-var $ test-var sub-shell:g-var sub-shell:l-var $ echo $g-var :$l-var: GLOBAL :: $
  • 683. 9.7.3 局部变量和全局变量作用域 任何没有用export命令定义过的变量是局部变量,子shell不能存取父shell的局部变量。子shell中可以存取和修改父shell的全局变量,但这种修改对于父shell全局变量没有任何影响。在子shell中用export命令定义的全局变量和对此变量的修改对父shell变量没有影响。全局变量保持它的全局性,不仅能直接传递给它的子shell,而且子shell还能将它传递给子shell的子shell。在对变量赋值之前和之后的任何时候可以将该变量转换成全局变量。
  • 684. 9.7.4 程序调试 shell提供了多种工具以便在调试shell程序时使用,这些工具允许观察一个shell程序的执行,还允许观察一个程序在不做任何实际处理的情况下是如何被“执行”的。提供的测试方式有: 1. shell程序的详细跟踪 shell提供的详细跟踪特性允许用户观察一个shell程序的读入和执行,如果在读入命令行时发现语法错误,则终止程序的执行。命令行被读入后,shell按读入时的形式在标准错误输出中显示该命令行,然后执行命令行。详细跟踪shell程序的执行有两种方式:整个程序的详细跟踪和局部程序的详细跟踪。
  • 685. 整个程序的跟踪执行格式: sh -v 文件名用来实现对整个文件的脚本进行跟踪。 局部程序的跟踪执行格式:set -v——设置跟踪标志 set +v——关闭跟踪标志用来实现对文件中的部分脚本进行跟踪。
  • 686. 例: $ cat traced date echo $PATH|wc -c $ traced 1998年 11月 05日 星期四 17时 29分 59秒 CST 45 $ sh -v traced date 1998年 11月 05日 星期四 17时 30分 08秒 CST echo $PATH|wc -c 45
  • 687. 2. shell程序的跟踪执行 此功能允许用户观察一个shell程序的执行,它使命令行在执行前完成所有替换之后,在标准错误输出中显示每一个被替换后的命令行,并且在行前加上前缀符号“+”(但变量赋值语句不加“+”符号),然后执行命令。对shell程序的跟踪执行也有两种方式:整个程序的跟踪执行和局部程序的跟踪执行。 整个程序的跟踪执行格式为, sh -x 文件名 用来实现对整个文件脚本的跟踪执行。 局部程序的跟踪执行格式为, set -x——设置跟踪标志 set +x——关闭跟踪标志
  • 688. 用来实现对文件中部分脚本的跟踪执行。 例: $ cat traced date echo $PATH|wc -c $ sh -x traced +date 1998年 11月 05日 星期四 17时 30分 08秒 CST +echo /bin:/usr/bin:/usr/fk/bin /bin:/usr/bin:/usr/fk/bin +wc -c 25
  • 689. 3. 详细跟踪与跟踪执行的组合 整个程序的跟踪执行格式为, sh -vx 文件名 局部程序的跟踪执行格式为, set -vx——设置跟踪标志 set +vx——关闭跟踪标志 详细跟踪与跟踪执行的区别在于在执行命令行之前,详细跟踪打印出命令行的原始内容,而跟踪执行却打印出经过替换后的命令行内容,循环结构和管道线在两种跟踪方式中是根本不同的。由于shell对这些结构只读取一次,因此,详细跟踪方式也仅显示它们一次。但这类结构的命令行可能要被重复执行多次,所以,跟踪执行方式就可能将同样的命令行显示一次以上。
  • 690. 4. 非执行跟踪 shell的非执行任选项提供的功能允许用户观察一个shell程序,而程序中的命令行不被执行。非执行通常与详细跟踪结合使用,查看在不实际执行一个shell程序时,程序是如何被“执行”的。其格式为, sh -n 文件名 或 set -n
  • 691. 5. 未置变量退出跟踪 shell的未置变量退出特性允许对所有的变量进行检查,如果引用了一个未赋值的变量就终止shell程序执行。shell通常允许未置变量的使用,在此种情况下,变量的值为空。但如果设置了未置变量退出的任选项,则一旦使用了未置的变量就显示出错信息,并终止程序的运行。其格式为, sh -u 文件名 或 set -u——设置标志 set +u——清除标志
  • 692. 6. 立即退出跟踪 shell的立即退出特性允许在程序内的任何命令以非零状态退出时,立即终止程序的运行。其格式为, sh -e 文件名 或 set -e——设置标志 set +e——清除标志
  • 693. 9.7.5 shell程序的应用 1. shell程序的定义 若一个文件包含了一串简单命令串时,称为命令文件;若一个文件包含了一组更为复杂的命令组合(常常使用了shell的条件命令、控制结构和其他高级特性)时,就称之为shell程序(或称shell过程)。通常情况下,两者的称呼并没有明确的区别。 在shell程序设计语言里的基本操作是Linux系统命令,它是Linux系统中最有生气的部分,而且对于Linux系统的使用极为重要。
  • 694. 2. 何时使用shell程序设计语言 当一个问题的解决方法需要使用多个Linux系统的标准命令时,可使用shell命令文件。如果处理的问题比较复杂,可以使用shell程序设计语言,即在命令文件中定义各种参数和变量,使用shell的条件命令、控制结构和其他高级特性。
  • 695. 9.8 shell应用实例 下面这段程序取自/etc/rc.d/rc.sysinit文件中的一部分,/etc/rc.d/rc.sysinit文件是Linux系统启动过程中需要执行的shell程序。这段程序的功能主要是配置网络环境、检查文件系统和加载应用模块。要注意,在shell程序中注释语句是以#开头,但以#!开头的语句并不是注释语句。如果想执行该程序,可以用一般用户登录系统后,直接执行/etc/rc.d/rc.sysinit。
  • 696. # 第一条语句先指定本shell程序采用哪个shell执行。 #! /bin/sh # 以#开始的语句是注释行。 # /etc/rc.d/rc.sysinit - run once at boot time # # Taken in part from Miquel van Smoorenburg′s bcheckrc. # # 下面语句是定义变量PATH,并把PATH变量声明为全局变量。 # Set the path PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH
  • 697. # 下面命令读取配置数据,这里用到一个简单的IF语句。 # 判断/etc/sysconfig/network文件存在否,如果该文件存在,就执行它。 # 否则,给NETWORKING变量赋值,给HOSTNAME变量赋值。 # Read in config data. if [-f /etc/sysconfig/network]; then . /etc/sysconfig/network else NETWORKING=no HOSTNAME=localhost fi
  • 698. # 下面语句的功能是启用交换,执行shell命令swapon。 # Start up swapping. echo ″Activating swap partitions″ swapon \|a # 以下语句设置主机名。 # 下面语句引用hostname变量,执行hostname命令。 # Set the hostname. hostname ${HOSTNAME} echo hostname: `hostname`
  • 699. # 下面语句设置NIS域名,其中引用$NISDOMAIN变量,执行shell命令domainname。 # Set the NIS domain name if [-n ″$NISDOMAIN″]; then domainname $NISDOMAIN else domainname ″″ fi # 下面是一段简单的if语句,判断/fsckoptions文件是否存在, # 并定义fsckoptions 变量。 if [-f /fsckoptions]; then fsckoptions=`cat /fsckoptions` else fsckoptions=′′ fi
  • 700. # 下面是一段简单的if语句,判断/fastboot文件是否不存在。 # 其中,引用fsckoptions 变量,执行shell语句fsck。 # 并引用系统变量$?,定义变量rc,获取上一个shell语句的执行结果。 if [! -f /fastboot]; then echo ″Checking root filesystems.″ fsck -V -a $fsckoptions / rc=$? # 以下这段语句是检查文件系统的执行结果, # 如果$rc 大于1,说明文件系统有严重问题,并显示信息。 # 其中,给环境变量PS1赋值,执行shell命令sulogin, # 执行shell命令umount a,执行shell命令reboot。 # A return of 2 or higher means there were serious problems. if [$rc -gt 1]; then echo echo echo ″*** An error occurred during the file system check.″ echo ″*** Dropping you to a shell; the system will reboot″ echo ″*** when you leave the shell.″
  • 701. PS1=″(Repair filesystem) #″; export PS1 sulogin echo ″Unmounting file systems″ umount a mount -n -o remount, ro/ echo ″Automatic reboot in progress.″ reboot # 下面语句是嵌套的复合条件if语句,执行shell命令quotacheck elif [″$rc″=″1″ -a -x/sbin/quotacheck]; then echo ″Checking root filesystem quotas″ /sbin/quotacheck -v/ fi fi
  • 702. # 下面语句对根系统实行磁盘空间限定,执行shell命令quotaon。 if [-x/sbin/quotaon]; then echo ″Turning on user and group quotas for root filesystem″ /sbin/quotaon/ fi # 下面命令是设置PNP,首先检查参数,执行shell命令mount。 # 在if语句中采用输出重定向,定义变量PNP。 # check for arguments mount -t proc/proc/proc if grep -i nopnp/proc/cmdline>/dev/null; then PNP= else PNP=yes fi
  • 703. # 以下语句设置PNP, 先使用一个简单if语句,复合条件,并引用变量PNP。 # 执行shell命令isapnp。 # set up PNP if [-x /sbin/isapnp -a -f /etc/isapnp.conf]; then if [-n ″$PNP″]; then echo ″Setting up ISA PNP devices″ /sbin/isapnp/etc/isapnp.conf else echo ″Skipping ISA PNP configuration at users request″ fi fi
  • 704. # 下面命令重新mount根文件系统,执行shell命令mount # 如果/etc/HOSTNAME不存在,则把${HOSTNAME}变量的值输出到/etc/HOSTNAME文件中。 # Remount the root filesystem read-write. echo ″Remounting root filesystem in read-write mode.″ mount -n -o remount,rw / if [! -f /etc/HOSTNAME]; then echo ${HOSTNAME} > /etc/HOSTNAME fi # 清空/ etc/mtab文件 # clear mtab >/etc/mtab
  • 705. # 执行shell命令,把/和/proc文件系统加载上。 # Enter root and /proc into mtab. mount -f / mount -f /proc # 如果/proc/ksyms文件存在, 定义变量USEMODULES为y。 if [-f /proc/ksyms]; then USEMODULES=y else USEMODULES= fi
  • 706. # 下面命令是获取要执行的模块。 # 先执行shell命令rm删除文件, 引用变量USEMODULES, # 并用set给位置变量强制赋值,引用系统变量$#,引用位置变量$1, # 在if语句中使用管道命令,使用输出重定向。 # Get the modules ready to go -- we use awk here as cut is in /usr/bin rm -f /lib/modules/preferred if [-n $USEMODULES]; then set `cat /proc/cmdline` while [$# -gt 0]; do if echo $1|grep ′^BOOT-IMAGE=′ > /dev/null ; then # # # 中间略去部分语句 # # 下面语句初始化串口, 执行shell命令rc.serial。 # Initialize the serial ports. if [-f /etc/rc.d/rc.serial]; then . /etc/rc.d/rc.serial fi
  • 707. # 下面语句加载模块, 执行shell命令rc.modules。 # Load modules (for backward compatibility with VARs) if [-f /etc/rc.d/rc.modules]; then /etc/rc.d/rc.modules fi # 下面语句是检查SCSI磁带设备。 # If a SCSI tape has been detected, load the st module unconditionally # since many SCSI tapes don′t deal well with st being loaded and unloaded # 这里用到带复合条件的if语句,并使用管道命令和重定向命令。 if [-f /proc/scsi/scsi] && cat /proc/scsi/scsi|grep -q ′Type:Sequential-Access′ 2>/dev/null ; then if cat /proc/devices|grep -qv ′ 9 st′ ; then if [-n ″$USEMODULES″] ; then # Try to load the module. If it fails, ignore it... modprobe st 2>/dev/null fi fi fi
  • 708. # 下面执行shell命令dmesg,显示系统配置信息, # 并把输出结果重定向到/var/log/dmesg中。 # Now that we have all of our basic modules loaded and the kernel going, # let′s dump the syslog ring somewhere so we can find it later dmesg > /var/log/dmesg # 执行shell命令random start。 # Feed entropy into the entropy pool /etc/rc.d/init.d/random start
  • 709. 9.9 小结 本章主要介绍了什么是shell、shell变量、shell命令以及shell 语言控制结构,并着重讲述了如何使用shell语言编写shell程序并调试运行。大家要充分理解shell变量,通过编写shell程序并运行,来理解shell程序在整个Linux系统所起的巨大作用。
  • 710. 习题 9-1 什么是shell?什么是重定向?什么是管道? 9-2 shell变量怎么用?常用的预定义变量和环境变量都有哪些?常用的位置变量和系统自动赋值有哪些? 9-3 往你的主目录下随便拷贝5个文件,用mv命令将这些文件名都变成大写,现在请你编个shell程序,将这些文件名都变成小写。 9-4 编写一个shell程序,它能够将指定目录及其子目录中的包含字符串root的文本文件找出来。
  • 711. 第3部分 系 统 管 理 第10章 Linux系统软件的获取和安装10.1 硬件需求 10.2 Linux上可用的软件1.3 操作系统功能 10.3 Linux系统软件的获取途径 10.4 Linux的安装 10.5 软件包及模块的安装与加载 10.6 配置与创建内核 10.7 系统的引导与关闭 10.8 XLinux的安装示范 10.9 小结 习题
  • 712. 系统管理指安装操作系统并对系统进行日常管理和维护,以保证这个系统安全、可靠地运行,保证用户合理、有效地使用系统资源,使得每一个用户方便、高效地运行并完成其任务。 本书系统管理部分的内容主要是针对运行于Intel平台的Linux,其他平台(如Sparc和Alpha)上的安装和应用只做简单介绍。 通常Linux的安装可以从光盘安装,安装程序会自动检测设备,当然也可以从FTP站点安装或者从NFS服务器安装,本章选择XLinux和Red Hat作为实例,详述安装需求、安装过程及其配置。
  • 713. 10.1 硬件需求 在安装Linux系统之前,需要了解自己的硬件环境。包括以下几个主要方面:CPU的主频和型号;硬盘是IDE的还是SCSI的;有几块硬盘,分别有多大;如果有RAID卡也要知道卡的型号和厂商;内存有多少;鼠标是串口的还是PS/2的;显卡与显示器的厂商与型号,有多少显存以及网卡的厂商与型号。所有这些信息对于重新编译内核非常重要。
  • 714. 目前国内较流行的Red Hat的Linux发行版本,它在Intel平台上的运行,要求CPU为386或以上。对于内存来说,一般至少要有4MB以上,使用图形界面则需要更多的内存。总之,内存多多益善,因为Linux会充分利用空余内存作为高速缓冲区,有利于提高系统性能。 对于XLinux需要586 P 133以上的Intel处理器,AMD、Cyrix CPU亦可,若计划安装XLinux作为提供两种以上服务的服务器,最好使用PentiumII 266以上的CPU,至少64MB RAM的物理内存,4.3GB以上的SCSI或是IDE硬盘,当然内存要越多越好。XLinux可支持4个CPU。
  • 715. 10.2 Linux上可用的软件 大部分常用的UNIX工具和程序已经移植到Linux上了,包含大部分的GNU程序和许多X client。其实移植这些软件到Linux上是很容易的事,大部分的程序源代码在Linux上重新编译时都不须修改或只要部分修改即可,因为Linux几乎完全符合POSIX的标准。可惜目前Linux上供普通用户使用的套装软件并不很多,尤其是家庭娱乐与办公方面。以下是一些可在Linux上运行的常用工具及软件: 基本的POSIX兼容的UNIX指令: 如ls,tr,sed,awk等 软件开发与管理工具: 如gcc,gdb,make,bison,perl,rcs,cvs,gprof,automake等
  • 716. X Windows环境: X11R5(XFree 2.1.1),X11R6(XFree 3.1)等 文本编辑器: 如GNU Emacs,elvis(GNU vi),vim等 shells: 如bash,zsh,ksh,pdksh,tcsh,csh,rc,ash等 通讯程序: 如UUCP,kermit,minicom,pcomm,xcomm,term等 news和mail: 如c-news,innd,trn,nn,tin,smail,elm,mh,pine等 排版软件: 如tex,groff,doc等 PostScript软件: 如Ghostscript,GhostView(XWindow)等
  • 717. 10.3 Linux系统软件的获取途径 Linux作为开放源代码方式发行的软件,其主要发布方式是通过网络进行,可以在就近的FTP站点上找到许多最新的Linux发行版本,并且可以找到许多软件包,这些软件包通常以GNU的版本发行,许多Linux发行版本都包含了其中的大多数,并且各发行厂商也自行开发了一些有特色的管理工具和实用软件包。还有许多媒体发行的光盘,这对于安装非常便利。如果是从网络下载的发行版本,录制光盘时一定要注意其目录结构,否则可能无法安装。 XLinux软件可以通过网址ftp.xLinux.com.tw获得,也可以从XLinux镜像(mirror)站点列表中下载。
  • 718. 10.4 Linux的安装 安装依赖于软件介质及硬件配置,下面详述Red Hat Linux的安装过程。一般可以通过光盘直接启动来安装Red Hat系统,设在DOS下光驱路径为F:\,可以按以下步骤进行。 C:\> F: F:\> cd \dosutils F:\>dosutils> rawrite Enter disk image source file name: PATH\boot.img Enter target diskette drive: a: Please insert a formatted diskette into drive A: and press --ENTER-- : F:\dosutils>
  • 719. 当rawrite.exe要求输入软盘镜像的时候,输入完整的“boot.img”的路径名,把软盘插入A驱。当程序问你把镜像写入哪个软盘驱动器的时候,输入“a:”。 启动盘也可以在类Linux操作系统下制作,mount上光驱后,将当前目录改为映像文件boot.img所在的目录,执行以下命令(根据需要修改映射文件的文件名和软盘设备名): # dd if=boot.img of=/dev/fd0 bs=1440k 以下是安装步骤:
  • 720. (1) 选择语言、键盘类型及鼠标类型 (2) 安装类型和方法 RedHat Linux 6.1有典型、自定义等几种方式,如果采用自定义方式,最好选择“everything”,安装完后,再根据需要删除不用的软件包,如果空间不足,可以自行选择需要的软件包,同时要选择模块相关性检查,以避免不必要的错误。 (3) 磁盘分区 磁盘分区有一些较好的做法,比如“/boot”分区独立作为只读分区加载,可以避免该文件系统被破坏,另外要将“/var”分区独立出来,如果是作为邮件服务器,还需要有一个大的邮件信箱分区“/var/spool/mail”,根文件系统“/”也必须独立,
  • 721. 因为这里面的配置文件至关重要,根文件系统尽量保持不变有利于系统的稳定性。以上这些分区所采用的标准就是要保证文件系统的可靠运行,将易于变化的文件系统独立出来,不至于由于某些文件系统如“/var、/usr、/home”等的空间不足而占用其他文件系统如根文件系统的空间。此外,安装Linux时,还需要设置一个交换分区,分区类型为“swap”,它用来把内存中不常用的数据和程序交换到硬盘上,尽管有些服务器有足够的内存用作缓冲区,提供一点swap分区还是有助于提高系统性能的。RedHat6.1之前交换分区有127.8MB的大小限制,不过以后版本支持更多的交换空间。
  • 722. Linux下分区可用的工具有Disk Druid(图形界面)、fdisk等,XLinux也有自己的图形化分区工具,非常方便易用。建议初学者采用图形化分区工具,只有对系统有了一定了解以后才可以尝试使用fdisk。 以Disk Druid分区工具为例,选择“Add”添加新的分区,“Edit”改变分区,“Delete”删除分区,“Reset”恢复原来的分区状态。每个分区要求添加的信息有: Mount Point: 分区要装载的文件系统名 Size: 分区的大小,以MB为单位 Partition Type: 分区类型。Linux的文件系统要使用Linux native类型的分区,Linux交换分区用Linux Swap类型。
  • 723. fdisk的常用命令如下: m列出所有可用的命令 p 打印当前分区表信息 n 添加新的分区 t 设置或者改变分区的文件系统类型 l 列出文件系统类型及它们ID号的列表,如83为Linux native,82为Linux swap w 保存分区设置信息并退出fdisk q 不保存直接退出fdisk
  • 724. 磁盘设备一般有IDE与SCSI两种,IDE硬盘名称为“/dev/hda、/dev/hdb”等,SCSI硬盘名称为“/dev/sda、/dev/sdb”。不过SCSI硬盘因为具有高速缓存和更快的速度,无论是性能还是稳定性都优于IDE硬盘,适合用在服务器上。
  • 725. (4) 选择和安装软件包 分区创建完之后,还不能在该分区上安装文件系统,要安装文件系统必须做好准备工作,即格式化分区和创建文件系统。可以选择想要格式化的分区,并选中“Check for bad blocks during format”选择框。 一般Linux会在安装软件之前自动格式化和创建文件系统,但是软件包的选择是在格式化之前,如果是出于试验的目的,可以选择“everything”,如果较为熟悉Linux系统了,可以根据需要选择相应的软件包,不过建议安装所有的联机文档。 完成以上工作就可以让机器完成磁盘分区的格式化、文件系统的创建、软件包的安装等工作。
  • 726. (5) 配置工作 许多配置工作都可以在系统运行过程中进行,不过安装程序在安装完毕时提供了图形化的配置界面,可以在此配置网络、配置显示卡、设置root密码、添加用户等等,不过进行安全验证的配置时一定不要忘了加上以下选项:Enable shadow passwords Enable MD5 passwords此处有许多配置界面,实际上它们都有对应的应用程序,常用的有timeconfig、userconf、linuxconf、netconf等,其他的如键盘鼠标配置程序kdbconfig、mouseconfig等。
  • 727. 一般安装Linux都要安装LILO引导程序,该程序用于Intel平台,Sparc平台采用Silo,Alpha平台则使用Milo。可以选择把LILO装在主引导扇区(MBR)或引导分区的第一个扇区,一般情况下LILO安装在主引导扇区,但是如果系统装了其他的引导程序,为了不破坏它们,就必须安装在引导分区第一个扇区,要从该分区启动系统,就必须先激活该分区。
  • 728. 安装程序还提供了几种不同的测试信息,把这些信息放在五个虚拟控制台上,可以用Alt+Fn在它们之间切换。当安装Linux遇到困难时,虚拟控制台提供的信息非常有帮助,它可以使您发现问题所在。其中:Alt+F1为安装的对话框;Alt+F2为外壳(shell)提示符;Alt+F3为安装日志(来自安装程序的信息);Alt+F4为系统日志(来自内核的信息);Alt+F5为其他信息。 如果对Linux系统很熟悉的话,也可以选择从ftp站点安装、从NFS服务器安装、SMB安装以及从硬盘安装。但是上述安装都需要启动盘,除了SMB安装外,还需要支持盘。
  • 729. 10.5 软件包及模块的安装与加载 传统的UNIX操作系统如Solaris,用户应用程序一般安装到/usr/local目录下后,配置文件和可执行命令也放在相应目录下,如/usr/local/etc、/usr/lcoal/bin。Linux下应用程序的目录组织以套件的形式出现,这和大多数UNIX版本有很大区别,其配置参数通常放置在/etc目录下,可执行命令放在/usr/sbin或/sbin中。无论是RedHat的RPM软件包管理方式还是Debian的dpkg,都采用这种方式。但是它也有/usr/local目录,可以迎合那些喜欢自己编译和安装软件包的系统管理员的口味,实际上作为应用服务器,这种方式更符合要求,不过要注意设置好与路径相关的环境变量,如MANPATH等。
  • 730. 下面将介绍RedHat的软件包管理工具RPM,有兴趣的读者可以自学Debian的dpkg,但是dpkg需要有一定的Linux使用经验,只有熟悉了Linux系统才可以去涉足,它对于想更深入地了解Linux系统非常有帮助。 RPM(Red Hat Package Manager)可用来安装、卸载、升级、查询、验证和创建软件包。利用RPM创建的软件包是一个档案文件,以“.rpm”作为后缀,它包含文件、软件名称、版本等信息,下面分别介绍RPM的主要功能:
  • 731. (1) 安装软件包: rpm -i可选参数 软件包.rpm rpm可选参数如下: -v显示安装的软件包名称。 --test 演示安装过程但并不实际安装任何内容 --nodeps 安装前不执行软件包依赖性检查,但不推荐使用 --force 强制安装一个软件包 -h打印50个“#”符号,与-v合用,使显示的内容更美观 -vv显示rpm命令完成的工作 如:# rpm -ivh input-1.4.linux-1.i386.rpm
  • 732. (2) 卸载软件包: rpm -e可选参数 软件包名称 参数“--test”,配合“-vv”使用,能够使RPM演示删除软件包的操作过程,但实际上并不删除任何文件。另外有些软件包是其他软件包运行必需的组件,要删除它们就会打破这种依赖性,导致其他程序不能正常运行,如果要强行删除,可以使用“--nodeps”通知RPM卸载前不检查软件包依赖性。 (3) 查询软件包: rpm -q可选参数 软件包名称 rpm -q的用法如下:
  • 733. rpm -ql列出软件包的所有文件,包括配置文件、文档文件等 rpm -qs 列出软件包中所有文件的状态 rpm -qd 列出软件包中所有的文档文件 rpm -qc列出软件包中所有的配置文件 rpm -qi 列出软件包的综合信息 rpm -qa 列出系统中安装的所有软件包 rpm -qf 文件名列出拥有指定文件的软件包 rpm -qp 包.rpm列出该文件对应的软件包名称 如: #rpm -qp chinput-1.4.linux-1.i386.rpm 查询该软件包会在系统中安装哪些文件
  • 734. (4) 验证软件包: rpm -V软件包名称 它将软件包的信息与初始安装时存储在软件包数据库中的信息进行对比,比如有人安装了木马程序就可以通过这种方式查出来,不过这个方法不是很安全,建议大家安装完毕时备份/var/lib/rpm/目录下的内容,最好放到另一台主机上。如果没有问题就不输出任何结果,如果有问题,会输出一个8位字符的字符串,每一位字符代表一种错误,没有错误就用“.”表示,这些字符依次有: S 文件大小改变 M 文件的模式改变(文件权限和文件类型) 5 MD5校验和改变 D 设备变化
  • 735. L 符号链接变化 U 文件属主变化 G 文件属组变化 T 文件修改的时间变化 还可以用以下命令校验包含某个特定文件的软件包,如果文件丢失,还会报告文件状态为“missing”。 rpm -Vf 文件名 (5) 升级软件包: rpm -U可选参数 软件包名称 实际上是卸载和安装的组合,不过会保留配置文件。另外一个参数是“-F”,它也可以升级软件包,不过要求存在一个早期版本。升级软件包的可选参数与安装时的参数一样。
  • 736. 10.6 配置与创建内核 Linux的内核更新非常快,用户要跟踪这些变化就必须经常编译内核,将系统升级,这样可以保证系统更加稳定安全。如果不是出于试验目的,必须选择稳定的内核版本,可以用下面的命令查看当前内核版本信息。 # uname -a Linux dns 2.2.14-6.0 #1 Tue Mar 28 16:56:56 EST 2000 alpha unknown 依序为:系统名称、主机名称、发布版本信息、操作系统类型、机型
  • 737. 从以上信息可以看出该系统内核的版本号为2.2.14,第一个2为主版本号,很少变动,除非有了重大改进,第二个2是次号,表明系统的稳定性,偶数表明该内核比较稳定,奇数表示该内核正在改进,处于开发与实验阶段。14是该版本的修订号,表明该版本的当前增补级。 编译内核是非常简单的工作,但是要根据自己的需求配置一个适合自己的内核就不容易了。一般原则是尽可能去掉不用的模块,常用的模块编译进内核而不采用加载模块的方式,尽量采用稳定的版本等等。
  • 738. 编译前通过“make config、make menuconfig(图形界面)”配置参数,一般采用图形比较容易,适合新手,不过这仍然需要对系统比较了解才能胜任。如果在XWindow下并且希望有图形界面,应采用make xconfig方式。如果你的机器有一些较新的硬件或其他比较特殊的设备,可能会在安装设备驱动程序时遇到麻烦,建议去相关厂家的Web站点去寻找答案。对于新手来说,采用图形界面还有一个好处,因为该图形界面提供在线帮助,可以在选择某项模块之前,用“?”获得帮助,新的内核都有很详细的讲解,注意看相关的操作提示,将有助于提高对系统模块功能的认识。
  • 739. 接下来用“make dep”分析内核的配置并创建相应的相关树,以确定要安装哪些内容。接着用“make clean”清除所有以前编译留下的二进制文件,建议采用更为有效的“make mrproper”或者“make distclean”命令。如果系统时钟在上次编译后更改过,最好用“touch”更新文件访问时间为当前系统时间。然后用“make zImage”执行整个编译过程,有时采用这种方式会出现内核太大的错误,这时可以使用“make bzImage”来创建内核。最后要编译模块(如果选择了模块编译),使用“make modules”、“make module-install” 和“depmod -a”以编译和安装模块,安装模块实际上就是将它们复制到相应的目录下,一般为/lib/modules。
  • 740. 接下来就是将新编译的内核拷贝至/boot目录下,并改动LILO的配置文件/etc/lilo.conf。新内核最好以其版本号标示。操作过程如下: # cp/usr/src/linux/arch/i386/boot/bzImage/boot # mv bzImage vmlinuz-2.2.17 # ln -s vmlinuz-2.2.17 vmlinuz 同时要将/etc/lilo.conf文件中的image指向该新内核,参考下一节LILO的配置部分。
  • 741. 10.7 系统的引导与关闭 10.7.1 系统引导程序LILO Intel平台上运行的Linux系统可以通过LILO引导程序引导,也可以通过在DOS中运行loadlin.exe程序引导。还有其他的引导装载器如System Commander也可以满足要求,本章主要讲解LILO的使用。 与LILO有关的文件如下 /sbin/lilo可执行程序,用于安装内核映像 /boot/boot.b 引导装载器 /boot/map 引导映像,它包含内核的路径 /etc/lilo.conf LILO的配置文件
  • 742. 下面讲解如何修改和定制配置文件lilo.conf。该文件中各条目是用来通知内核怎么进行工作的,其内容规定如下: 栏目 说明 boot=<引导设备> 引导扇区的设备名称,如果没有该项,将从安装为root的设备上读取引导扇区。 Linear 生成线性扇区地址来代替扇区/磁头/柱面地址,有些SCSI设备需要该选项。 install=<引导扇区> 安装指定的文件作为引导扇区的内容,默认为/boot/boot.b images=<内核映像> 指定内核的路径和名称 verbose=<级别> 用于说明信息,级别越高,越详细,最高级别为5
  • 743. root=<引导扇区> 设备名称,如/dev/hda1 Prompt 要求输入引导提示信息。 timeout=<时间> LILO等待键盘输入的时间,单位为1/10秒。 Lable 引导内核的名称 Default 当同时安装了几个系统时,默认启动的引导内核名称 如果对lilo.conf做过修改,就必须运行/sbin/lilo程序。 通常情况下可以不用干预,系统就能够启动,如果系统不能启动,可以输入“rescue”进入修复模式,或者输入“linux 1”进入单用户模式,然后手工修复文件系统。
  • 744. 10.7.2 系统启动与关闭的相关脚本与命令 相对来说,通过修改某些配置文件更容易控制和理解系统的行为。系统的初始化脚本可以通过/etc目录下的某些文件来修改。 UNIX/Linux系统共设有六种运行级别,可以通过“init”命令引导,其值规定如下: init 0:终止系统的运行 init 1:单用户模式,一般用于系统维护目的 init 2:多用户模式,但不支持NFS init 3:多用户模式,一般服务器都在此级别上运行 init 4:保留 init 5:XWindow启动模式 init 6:重新启动系统
  • 745. 默认的运行级别在/etc/inittab文件中设定如下: id:3:initdefault: 如果希望启动图形界面,则设置为5。 接下来对系统初始化,这是通过/etc/rc.d/rc.sysinit文件进行的,只需根据自己的需要修改相关的内容。 系统接下来就要启动各个相应运行级别的脚本了,这些脚本位于/etc/rc.d/rc?.d目录下,?代表1到6的数字,以rc3.d为例,该目录下的文件分别以S和K开头,S代表系统启动时应该启动的应用程序,K表示系统关闭时应该终止的应用程序。数字代表启动和关闭的顺序,数字小的先执行。随后的名称对应相关的程序,一定不要随便更改链接,否则无法启动该程序。
  • 746. 系统关闭还涉及到许多其他操作,因为关闭系统必须杀死所有用户进程、系统守护进程和其他进程。一般可以通过以下命令完成:init、shutdown、reboot、halt等命令。这些命令之间有些可以替代使用,如halt就相当于“shutdown -h”命令,reboot相当于“shutdown -r”命令。 下面对shutdown的功能进行详述,shutdown可以将系统安全地带入关闭状态,其命令格式如下: # shutdown [-t sec] [-arkhcfF] time [warning-message] 可选参数: t sec该参数表示给进程发送警告信息和杀死信息之间的时间,sec代表秒数
  • 747. a 使用/etc/shutdown.allow文件 r 关闭后重新启动 h 关闭系统,相当于halt和“init 0” k 仅给所有用户发送警告信息,而不关闭系统 c 取消正在运行的shutdown f 快速重启,即不进行fsck F 重新启动时强制运行fsck time 关闭系统的时间,单个数字表示多少分钟后系统关闭,如果要给定确切时间,可以用hh:mm的格式,即几点几分关闭系统 warning message 发送给所有用户的信息
  • 748. 也可执行# shutdown now立即关闭系统。 shutdown命令在脚本中也有应用,如inittab文件中。建议管理员使用这些命令,而不是使用给init进程发送信号的方式。
  • 749. 10.8 XLinux的安装示范 XLinux的安装分为一般安装(X-Linux)、快速自动安装(Express)和软盘安装(Floppy)3种安装模式。安装程序和配置工具(Genie)使用图形界面与对话框的操作方式工作。 10.8.1 安装前的准备工作和安装 将XLinux启动光盘放入光驱中,将BIOS设成光盘启动后重新启动计算机。选择合适的安装语言。 1. 磁盘分区 假设你的硬盘没有经过分区,XLinux会提示询问你是否将硬盘初始化。使用IDE硬盘时,引导分区必须全在前面1024个磁道内。
  • 750. 一些新版的BIOS和IDE硬盘可处理多于1024的磁道。如果不能确认,还是把启动分区放在前1024磁道内。 改变分区大小一般要求首先备份此分区想保留的所有东西(为防万一,最好备份整个硬盘),然后删除此分区,创建新分区,最后回存所有东西到新分区。如果是扩大分区,可能需要调整相邻分区的大小(并备份、回存)。 XLinux为用户提供两种方便的磁盘分区方式:
  • 751. (1) 智能型磁盘分区工具 它会自动判断硬盘中是否有空白扇区,然后会将空白扇区全部归XLinux使用。如果找不到空白扇区,将会询问是否要把全部扇区清除。此种分区方式将节省许多的时间,只要将要安装的扇区空出来,或者要将整个磁盘给XLinux时,不需作任何磁盘分区的规划,它将以默认的方式进行磁盘分区。 (2) 专业型磁盘分区工具 专业型磁盘分区工具提供全功能图形界面的分区方式,它可任意分割扇区大小,选择扇区类型,选择启动扇区,只要利用鼠标就可以完成磁盘分区,如图10.2所示。
  • 752. 图10.2 磁盘分区
  • 753. 当要新增一个磁盘区块,请输入你要分区区块的大小,选择磁盘类型,磁盘类型可参考表10.1。 最后,选取引导XLinux的分区,引导分区对应的状态区将会有“boot”的字样显示。当配置好分区的大小和分区类型后,根据系统提示将配置写入磁盘分区表。
  • 754. 2. 规划虚拟内存 通常,安装Linux需要建立至少两个分区供Linux使用,一个是Linux固有分区,另一个是Linux内存交换分区。一般如果系统内存在32MB以内,可以将交换分区配置为RAM的两倍。RAM超过32MB的,就不必拘于两倍的原则。但是请不要超过128MB,因为Linux一次最大只能处理128MB的swap。 swap也可以多分割几个,这样对于整体的性能有益,分割为一个固有分区和一个Linux内存交换分区,这种分割法是相当缺乏安全性的,要是root分区毁损的话,恢复整个系统可能只能重装。若是要在网络上当服务器的话,最少也应该分割成/(root)、/usr、/usr/local、/var、/home等。
  • 755. 根据窗口的提示信息,配置虚拟内存空间,在对应的【启动】和【检查】区域单击【是】或【否】来启动或检查虚拟内存空间。当配置好后,单击【下一步】,继续安装前的准备工作。 3. 文件系统规划 用户可根据用途及喜好,参考表10.2配置及规划文件系统。
  • 756. 表10.2 文件系统规划参考表格方法分区容量大小说明懒人分割法/ SWAP原则:除了SWAP的空间以内存的两倍大分割之外,其余全部给/使用,不需要再划分其他分区。最懒惰的分割法,但建议第一次安装Linux的用户先采用这样的分割法,等熟悉系统后再根据自己的习惯重新分割。帅气分割法/ /usr /home SWAP100M 多多益善 多多益善 内存×2把常常读写的/usr与/home分别割出两个分区,以确保系统发生故障时,可以保全数据。愚公分割法/ /usr /usr/local /usr/X11 /var /root /home SWAP50M 多多益善 视情况而定 视情况而定 150M 视情况而定 多多益善 内存×21. 因为XLinux习惯使用/usr放置软件,所以建议/usr越大越好。 2. /usr/local是用来放置一些特殊的软件,可以放自己或user写的软件,请根据自己的情况,调整这个分区大小。 3. /usr/X11主要放置XWindow的软件,如果根本不会用到XWindow,那么就可以把这个分区的空间缩小,让给其他分区使用。
  • 757. 4. 选择软件包 在相应的窗口选择你要安装的XLinux软件包组合。例如你可选择: (1) 全部软件包 (2) 最小系统安装 (3) 用户自行选择 选择好后单击【确定】按钮,可看到软件包详细列表,在此选择你要的软件包。 5. 设置引导管理器 如图10.3所示,在此窗口你可设置引导管理器(LILO)要引导的分区。
  • 758. 图10.3 设置引导管理器画面
  • 759. LILO是LInux LOader的简称,是Linux的引导程序,它主要的功能就是在Linux系统启动的时候,用来加载Linux的系统内核,除此之外LILO还可以用来加载其他的操作系统,进行多重启动,或者也可以在启动的时候传递参数给Linux的系统内核。 LILO是一个Linux系统上必要的程序,一般在安装系统时就会把LILO安装在磁盘的主引导分区或根分区上面。它只在启动时起作用。当你更改了系统内核,或想要改变启动系统的默认参数时,就有必要重新安装LILO,重新安装LILO的工作可以通过一个名为“lilo”的程序来实现。这两个名称是一样的,大小写不同而已。
  • 760. 大写的“LILO”指的是启动程序,我们永远不会自己动手去执行这个程序。“lilo”指的是LILO的安装程序,通过这个程序来把LILO安装到正确的地方去,并设置LILO。LILO安装程序lilo的设置文件在/etc/lilo.conf。当用户以root身份执行lilo程序的时候,lilo就会去读取/etc/lilo.conf,并依照其内容安装LILO,在命令行执行lilo来安装Linux启动程序的时候有几个选项可以使用。 LILO安装的位置,若指定的是一个硬盘分区(如/dev/hda1),lilo会将LILO安装在此分区的第一个扇区之上,就是一般所谓安装在根分区的情况。若指定的是整个硬盘(/dev/hda),LILO就会被安装在该硬盘的MBR上面。
  • 761. 6. 设置启动软盘 如果你选择了要制作一张启动软盘,请在单击【是】之前放入一片空白的磁盘。 7. 开始安装 系统开始把XLinux安装到你的机器上。XLinux安装好之后按任意键或单击鼠标左键,光驱会自动弹出XLinux的光盘。此时,请将XLinux的光盘取出,系统将重新启动,进入XLinux安装的第2阶段。 在XLinux的第二阶段安装里,你可以选择要加装的额外的软件包,也可选择【否】,直接进入XLinux的后一阶段设置。如果跳过了这个阶段,也可在安装完后在command下执行“xlinstall”指令加装额外的光盘(软件包)。
  • 762. 10.8.2 安装后的设置 XLinux安装后的设置工作包括了以下几项:root管理员密码及普通用户账号设置,外围设备的自行检测以及组态设置,网络环境设置,调制解调器联机设置,系统时间、时区设置和X窗口系统设置。 1. 设置系统管理员密码 在设置系统管理员口令窗口,设置超级账号密码。 2. 主机设置 在主机设置窗口,利用三种选择设置主机网络环境: (1) 局域网(使用网卡) (2) 拨号上网(使用Modem) (3) 单机使用(没有网络)
  • 763. 3. 键盘设置 依国别语系设置键盘的种类。 4. 系统时间设置 可以依地区与时区设置主机系统时间,此设置会同时改变主机的时间与日期。 5. 服务及其他设置 按照窗口提示设置基本的服务器服务,如Apache网页服务器、nfs网络文件系统、Sendmail邮件服务器等。在安装完成XLinux后就同时完成所要配置的服务器启动选项设置。
  • 764. Linux系统默认提供6个字符界面的虚拟主控台供用户使用,可以在不同主控台登录,同时做不同的事,不会相互干扰,彼此可按Alt+F1~F6键来相互切换主控台。假如X顺利起动了,那么X会占据第7号主控台,按Alt+F7就可以切换到X的画面。
  • 765. 10.9 小结 任何操作系统都需要安装才能使用,熟悉系统的安装有利于对系统有更清晰的认识,因为安装过程需要了解系统的硬件环境,需要规划应用软件的安装和选择内核模块。系统管理员必须确切地了解本机的硬件与软件环境,才可能在系统发生故障时及时地判断并排除故障。
  • 766. 习题 10-1 网上有很多Linux系统下的软件,很多都是后缀为tgz或tar.gz的压缩文件,找到这样一个文件,解压缩并编译安装,注意阅读README和INSTALL文件。 10-2 试着在不改变内核版本的情况下,重新编译内核(注意首先制作恢复用的紧急修复盘)。
  • 767. 第11章 账 号 管 理11.1 了解账号管理 11.2 Linux系统中的归属关系模式 11.3 超级用户 11.4 其他特殊用户 11.5 普通用户 11.6 用户组策略 11.7 账号相关的配置文件 11.8 小结 习题
  • 768. Linux系统通过账号管理维护系统的安全性,防止用户非法或越权使用系统资源。本章介绍账号管理以及与用户账号相关的系统资源的归属和用户组的概念。
  • 769. 11.1了解账号管理 Linux是一个多用户系统,与单用户的MS-DOS有很大的不同。单用户系统可以由使用者本人负责系统的安全性,而多用户系统中的所有用户都可以共享机器中的资源,包括软件资源和硬件资源。系统对每一个普通用户都设置一定的权限,让其在自己的组内自由工作,而不能跨越这种限制。同时对系统资源设置了访问控制表(access control list),即属主(文件拥有者)、组用户和其他人对资源的访问是可读、可写还是可执行。从这里可以看出,账号管理实际就是一种安全策略。它源自UNIX,在其他的多用户操作系统如Windows NT中也广为采用。
  • 770. 系统的这种安全机制有效地防止了普通用户对系统的破坏。例如存放于/dev目录下的设备文件分别对应于硬盘驱动器、打印机、光盘驱动器等硬件设备,系统通过对这些文件设置用户访问权限,使得普通用户无法通过覆盖硬盘而破坏整个系统,从而保护了系统。 用户账号一般包括普通用户账号、管理账号和系统账号。为了鉴别用户身份以及加强系统安全,系统为每个使用它的人分配了一个账号,这就是普通用户账号。每个人拥有一个独立的普通用户账号,每个账号有不同的用户名和密码。用户可以为自己的文件设置保护,允许或限制别人使用它们。用户账号被用来控制对系统的使用,只有拥有账号的人才
  • 771. 被允许使用机器。另外,账号还被用来确认用户,保持系统日志,用发送者的名字标记电子邮件,等等。 除了普通用户账号外,系统还提供了具有管理功能的账号,例如系统管理员使用的超级用户root,有了这个账号,管理员可以突破系统的一切限制,方便地维护系统。普通用户也可以用su命令使自己转变为超级用户。 # su password:(此处提示输入root的密码) 如果想回到原来用户账号,用exit命令即可。
  • 772. 系统中还有一些账号不能被人交互使用,通常这些账号只能被系统守护进程使用。它们经常必须以除root及普通用户账号外的某个特殊用户的UID访问某些文件。 系统管理员(拥有管理账号的人)的工作之一就是为系统中的所有普通用户添加账号。为了更好地理解账号管理的必要性,下面介绍Linux和UNIX系统中的归属关系模式。
  • 773. 11.2Linux系统中的归属关系模式 Linux和UNIX一样,其进程和文件都存在一个相关联的归属关系的概念。文件与进程的拥有者对其有绝对的控制权,可以控制文件和进程是否允许其他用户访问,这种权力只有root用户才可以超越。这些归属关系就是通过规划用户的权限来体现的。 Linux中,每个文件都有一个属主和属组,属主可以任意设置文件的访问权限。文件的访问权限包括属主的访问权限,属组的访问权限及其他人的访问权限。属主可以用chmod命令去修改,当然,万能的root也可以这样做。另外,root还可以使用chown和chgrp命令分别修改文件的属主和属组,但要注意,属主本身只有chgrp的权限,而没有
  • 774. chown这个权限。例如,文件file1的属主为dongyuan,属组为A,而用户dongyuan同时是A组和B组成员,则dongyuan可以用newgrp B命令改变自己当前的属组,进入B组,然后就可以使用chgrp将自己的文件属组改为组B。 例如,dongyuan使用chgrp改变file1的属组键入命令: # chgrp B file1 这样file1的属主仍为dongyuan,而属组变成了B。 root用户使用chown可以同时改变file1的属组和属主,例如键入命令: #chown lily:A file1
  • 775. 这样file1的属主仍为lily,而属组变成了A。 Linux中的每个进程也有类似的归属关系。每个进程都有4个关联的数值:实际UID,有效UID,实际GID,有效GID。通常情况下,实际ID与有效ID是相同的,进程的属主可以给进程发信号,也可以降低进程的优先级,但不可以升高,除非是root。而在某些特殊情况下(如设置了setuid或setgid位的程序进程),当该进程运行另一个用户的程序文件时,它的有效UID或有效GID分别被临时设置为该程序文件的属主的实际UID或实际GID,从而可以像该属主一样执行该程序文件。比如普通用户用passwd命令修改口令时,可以临时获得root权限,修改/etc/passwd文件的内容。简单地说,就是使程序
  • 776. 具备了属主的特权,而不是让程序使用者拥有程序属主的特权。 注意,setuid、setgid程序由其他用户执行时,返回的是该用户的shell,而不是程序属主的shell。否则,假如用户执行完这种程序返回后就变成了该程序的属主,那么要获得root身份,只要执行这么一个程序就可以了,系统就没有安全可言了。所以作为系统管理员,对这些程序要格外小心。 综上所述,账号管理就像是一把锁。劣质的管理就好比上了一把不用钥匙的锁,人人可以窥探你的隐私。对于如何保障个人权益,答案是两方面的,作为普通用户,不要把你的账号和密码告诉别人;作为管理员,要执行严格的账号管理。
  • 777. 11.3 超级用户 超级用户就是拥有root权限的用户。它在Linux或UNIX系统中拥有至高权限、能够胜任所有管理工作。在系统管理员手中,它是系统的守护神;在黑客手中,它就成为系统和管理员的灾难。 11.3.1 root的权威性和危险性 只要掌管了root,就拥有对系统内所有用户的生杀大权,对所有文件的处置权,以及对所有服务的使用权。当然,如果不小心敲错了命令,就可能给系统带来毁灭性的打击。一个普通用户只能在系统中做有限的事情,例如编辑自己的文件、修改本组的程序、建立自己的目录、决定别人以何种权限(可读、可写、可执行)访问自己的文件及目录,以及
  • 778. 同组的用户如何访问它们。而root不受这些限制,不管用户对自己的文件作了何种保护,root都能置之不理。这一方面体现了root的特权性,也从另一方面表现出了极大的危险性。例如,普通用户想删除目录/home/lily目录下的文件,执行以下命令: rm-fr /home/lily 但是不小心在home前多了一个空格,命令成了: rm-fr /home/lily 在Linux系统中,rm可以接受多个参数,即要删除“/”和“/home/lily”两个目录,而“/”表示整个文件系统。当然作为普通用户权限较小,系统不允许这么做。但是如果用户以root身份执行这个命令的话,没有任何方法阻拦他,可想而知,这对系统将是灾难性的。
  • 779. 另外一些特定的操作只能由root执行,如shutdown命令,该命令使用一个系统调用使系统脱机,但普通用户无权执行这个系统调用,否则系统的稳定性将难以预测。例如: # shutdown 10 The Server will be closed after 10 minutes 这个命令通知各个终端用户系统将在10分钟后关机,便于普通用户做好充分准备。 以上事实充分说明root是一把双刃剑,所以通常情况下系统管理员要为自己分配一个普通用户账号,必要时才用su命令将自己改变成为root,以避免因疏忽导致的意外错误。
  • 780. 正因为root用户拥有这种特殊的地位,保护超级用户的密码也就成了加强系统安全的关键。这样,从某种意义来说,对系统的管理问题也就成了对超级用户密码的管理。系统管理员要严格保护密码,并经常更换,而且密码要足够复杂、足够长,特别是对于重要的系统来说,更要建立严格的密码管理制度。 11.3.2 root的登录方式 前面已经提到一种登录方式,就是系统管理员以普通用户的身份进入系统,必要的时候再用su命令使自己转变成超级用户。不过su命令转换身份有一个环境变量转变的问题,读者可以用env命令查看身份转换前后的环境变量有何变化。
  • 781. 假设有一个用户要转变成root身份,请读者比较使用以下两条指令会有什么区别: (1) su root (2) su-root 这里的root是默认值,可以不敲。也可以用su转换成其他用户,前提是知道其密码。 格式同上: su 用户账号 su-用户账号 通过比较,我们可以看出使用第一条命令转变成root后,除了少数变量改变外,其他的变量几乎没有变化,好像继承了原用户的环境一样,变化的变
  • 782. 量根据不同的发行版本不同,如XLinux与RedHat就有差别。但是加上“-”后,环境变量就跟root直接登录时一样,即“-”的意思就是要使用root的环境变量。同样,这些规则同样适用于用su转换成其他用户账号的情况。 这种方式对于远程维护系统是绝对必要的,因为root不能从网络直接telnet登录主机。所以系统管理员要实现远程登录,就必须给自己分配一个普通账号。 另外一种登录方式就是从控制台直接登录,对于UNIX和Linux系统来说,前面我们提到超级用户主宰一切,实际上很有可能是“控制台”主宰一切。这里的控制台指的就是直接通过数据线连接到主机的显示终端。
  • 783. 对于Linux而言,普通的Intel平台的RedHat系统,只要在Linux启动时输入以下参数即可不需要密码进入单用户模式: boot:linux 1 而XLinux甚至可以直接从启动菜单中选择。即使启动过程不允许输入参数,也可以通过光盘或软盘启动进入系统,这些在安全部分再做介绍。当然对于商业模式,我们可以采用物理隔离的办法来保护主机。不过对于系统管理员来说,应该重视控制台的安全,养成良好的习惯。
  • 784. 11.3.3 与root环境变量相关的脚本文件 在root根目录下有几个重要的脚本文件,熟知它们的内容有助于更好地控制自己的行为,养成良好的习惯。如PATH环境变量一般没有当前路径“.”,这样就会督促系统管理员使用绝对路径。 root跟其他用户一样,其基本行为和环境变量由/etc/bashrc(以bash shell为例)和/etc/profile设定。root根目录下有两个配置文件.bashrc和.bash-profile,这两个文件可以由用户个人修改,以添加一些个人爱好的环境设置。修改后必须执行后方可生效,如修改完“.bashrc”文件后,执行如下: # ..bashrc
  • 785. 普通用户也可以自行设置自己的环境参数,建议读者动手修改这些脚本,只有试验过才会有更深的体会。 11.4 其他特殊用户 除了root和普通账号之外,系统中还存在一些账号,它们不能供任何人登录使用,只能由系统内核使用。这些账号有bin、sys、nobody、daemon等。这些账号在不同的操作系统中有很大区别,甚至名称也不一样,如AIX中的system就相当于sys。尽管其中许多已经没有被使用,Linux系统中仍保留了这些账号。Linux系统中更多地依赖管理员的安全意识,也体现了它是玩家的宠物,没有过多地考虑操作的安全性。
  • 786. 11.5 普通用户 任何一个提供用户服务的主机都需要对用户账号进行规划、管理,因为系统资源是共享的,又要保证用户的隐私,必须设置足够的安全屏障,一个认真负责的系统管理员就必须建好这个安全屏障。系统管理员一般都有大量的工具软件包,以帮助自己顺利、便捷地完成工作。为了让读者对工具的幕后工作有所了解,11.7节还将介绍如何通过修改配置文件达到目的。 11.5.1增加普通用户 Linux中有一条管理用户的命令useradd,还有一条命令叫adduser,这两者是一回事,adduser是useradd的符号链接。
  • 787. 通常情况下,增加用户可以不必指定用户的组,下面的命令会自动完成相应的工作,例如用下面的命令将为cheng创建一个普通用户账号:# useradd cheng系统默认处理用户ID与组ID相同,但是AIX和Solaris都需要指定用户组。同时命令脚本为用户创建主目录和相应的环境变量。 上面的命令实际上完成了以下几个工作: (1) 向/etc/passwd、/etc/shadow、/etc/group中写入用户信息 (2) 建立用户主目录/home/cheng (3) 将/etc/skel下的内容拷贝到/home/cheng下,为用户建立环境变量和准备脚本环境
  • 788. 读者可以自己通过试验比较文件内容的变化。如果通过root权限手工创建主目录,一定要重新设置该主目录及该目录下文件的属主和属组。 11.5.2设置用户口令 现在已经成功地在系统中添加了一个用户,但是用户还不能登录。为了让用户cheng使用系统,必须为cheng设置口令。不同的系统在处理用户口令的问题上也有不同的策略,Alpha的RedHat版本在设置口令之前会禁止用户登录,系统管理员必须为用户设置一个第一次登录使用的密码,可以使用如下命令: # passwd cheng
  • 789. 系统会提示你输入密码,并提示确认你的输入。只有当两次输入一致,密码设置才算成功。用户用这个密码登录以后可以自己修改密码,命令格式同上,即“# passwd”,然后根据系统提示输入密码,不过系统会要求你先提供老的密码,即未修改前的密码。 密码成功设置完毕,这个用户就拥有了系统的使用权。不同的用户可以设置自己的目录和文件访问权限。默认情况下,用户之间是不可以互相访问的。用户的密码信息保存在/etc/passwd和/etc/shadow配置文件中。
  • 790. 11.5.3删除用户 删除一个用户账户可以用命令完成,也可以手工进行,需要以下的步骤: (1) 删除/etc/passwd文件中此用户的信息记录。 (2) 删除/etc/group用户列表中出现的此用户,默认设置为一行。 (3) 删除用户的主目录以及由此用户创建的文件,还有此用户在/var/spool/mail中的信箱也要一并删除。 用命令userdel能完成所有这些工作。命令如下: # userdel-r cheng
  • 791. 注意,如果不加参数-r,userdel将保留用户的主目录,只删除其他的几项内容。 一般情况下,用户只有对主目录的写权限,随着主目录的删除,其相关文件也随之消失。但也有可能对该用户开放了其他的目录写权限,因此保存在其他位置的文件就要用find命令查找。利用find命令的-user、-uid选项可以很方便的找到属于某个用户的文件。命令如下: # find /-user cheng-ls 或 # find /-uid userid-ls
  • 792. 该命令用ls -l显示所有属主为cheng的文件。读者可以用以下命令查看find命令的功能,它带有许多参数,熟练使用它们可以带来许多便利。 注意: 使用-user选项时/etc/passwd文件中必须有用户的记录信息。当一条命令要用到用户的登录名或组名时,系统在执行这个命令的过程中,就需要根据/etc/passwd和/etc/group中的相关记录,将命令行中的登录名和组名转化为UID和GID。如果找不到相关的记录,系统就不能够识别给出的登录名和组名,这时就要直接使用该用户的UID和GID来标识用户。当管理员使用userdel命令删除了用户信息后,就必须根据用户的UID查找属于该用户的其他文件,UID就是上例中-uid参数后的userid。
  • 793. 11.5.4 禁用用户 有时,由于用户本身的原因或者考虑到系统安全的需要,需要查封一个账号。大多数系统都采用了shadow技术,对于这种系统,最简单的做法就是在/etc/shadow文件中找到该用户,并在其password域的前面插入一个“*”符号,以后要解封时只要删除这个标记即可。 如用户lily被禁用,则/etc/shadow中关于lily用户的表述为: lily:*$1$QRfSIh.2$6UokDtNIau1sjTsEAe3Kp0:11258:0:99999:7:::
  • 794. 另外有些版本的UNIX在/etc/passwd文件中对用户的password域符号有特殊规定,比如AIX 3中就规定“!”代表可登录账号,而其他符号表示该账号不可登录。对这类系统只要简单地在此处改写一下登录符号即可。 第11.7节将在配置文件中介绍什么是password域等概念。 11.5.5 修改用户信息 很多系统都提供了一些专用命令,如usermod、groupmod、chfn等等来修改用户信息,这些信息存放在/etc/passwd和/etc/group文件中;passwd命令可以用来修改用户密码,输入的密码经加密后,存放在/etc/shadow文件中。如修改用户所在的属组:
  • 795. # usermod-g B lily,即把lily的属组改为B。 修改用户的私人信息用chfn命令,运行时,对一般用户来说,要求先输入密码,再依次输入真实姓名、办公室地址、办公室电话、家庭电话等信息。 # chfn Changing finger information for lily. Password: Name []: lily Office []: 1407 Office Phone []: 6273845 Home Phone []: 4566653 这些信息将存入/etc/passwd文件中,这些信息可以通过finger命令查看。
  • 796. 修改用户的shell用chsh命令,同chfn一样,它也需要普通用户提供密码,也可以通过finger命令查看到修改后的信息如下: # finger lily Login: lily Name: lily Directory:/home/lily Shell:/bin/bash Office: 1407,627-3845 Home Phone: 456-6653 Never logged in. No mail. No Plan. 由上面的叙述可知,用户信息保存在3个文件中,/etc/passwd、/etc/shadow及/etc/group,所以直接修改这些文件也可以简单直观地达到目的。
  • 797. 11.6 用户组策略 组的概念对于管理用户的文件特别关键。用户可以决定自己的文件对同组的用户开放到什么程度,即可读、可写或可执行,或者三者的某个组合。对组外用户的访问限制可以更加严格,例如仅给只读的权限。 使用ls-l命令就可以看到每个文件的属主和属组,以及文件的权限。在11.2节中提到可以使用chown、chgrp、chmod等命令来改变目录及文件的访问权限。使用groups命令可以列出当前的注册用户所属的所有组的名称。
  • 798. Linux中如果创建用户时不指定用户组的话,系统默认地为用户生成一个组,其标识符GID与用户的UID是大小相等的整数。实际系统中,根据不同的需求,用户可以属于多个组,用户可以在不同的组中切换。11.2节中也提供了切换到另一个组的方法,即newgrp命令。用户组的相关信息在/etc/group配置文件中。 除了将用户添加到其他组以外,有些系统提供密码访问的方式访问其他组,这种方法安全性不是很高,很少采用。
  • 799. 11.7 账号相关的配置文件 11.7.1 passwd 文件在Linux系统中,用户账号的基本信息存放在文件/etc/passwd中,每个用户的信息占有一行。一个典型的passwd文件如下: root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin: daemon:x:2:2:daemon:/sbin: adm:x:3:4:adm:/var/adm: lp:x:4:7:lp:/var/spool/lpd: sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt
  • 800. mail:x:8:12:mail:/var/spool/mail: news:x:9:13:news:/var/spool/news: uucp:x:10:14:uucp:/var/spool/uucp: operator:x:11:0:operator:/root: games:x:12:100:games:/usr/games: gopher:x:13:30:gopher:/usr/lib/gopher-data: ftp:x:14:50:FTP User:/home/ftp: nobody:x:99:99:Nobody:/: gdm:x:42:42::/home/gdm:/bin/bash squid:x:101:101::/var/spool/squid:/dev/null cheng:x:500:500:cic:/home/cheng:/bin/bash
  • 801. 可以看出,passwd文件中每条用户记录都具有以下格式: 登录账号:密码域:用户标识符UID:组标识符GID:用户信息:主目录:用户shell(若为空格则默认为/bin/sh) 登录账号用来区分不同的用户,在系统中是惟一的。用户名的命名规则通常限制在8个字母或数字的组合之内。 现在的Linux系统通常都使用了shadow技术,将加密后的口令放在shadow文件中,而只在密码域中放一个“x”,改成其他符号也没有关系,主要是习惯问题。这样,一般用户就无法得到加密后的口令,增加了系统的安全性。
  • 802. UID是用户标识符,Linux中普通用户的UID默认为500以后的某个整数,系统在内部处理进程和文件保护时使用UID。UID应当是独一无二的,其他用户不应当有相同的UID数值。如果在/etc/passwd文件中有两个不同的登录账号有相同的UID,则这两个用户对相互的文件具有相同的存取权限。登录账号和UID相比较更直观,对用户来说,使用登录账号更方便,对系统来说UID更重要。 GID是组标识,表示用户所在组别的一个整数。组的概念对用户是相当重要的,一个组中可以包含多个用户,同组中的用户可以享有组内的特权,如可以访问相同的目录或文件等。默认添加用户时为用户分配一个和UID同等的组值。
  • 803. 用户信息域中存放用户相关的信息,如真实姓名、办公室地址、电话等。当然也可以不填写。同样可以通过chfn命令输入用户信息。 主目录域标明用户的主目录,当用户登录时,shell自动将主目录作为它的工作目录。普通用户的主目录一般放在/home下,例如用户cheng的主目录就是/home/cheng。 用户shell域是用户登录时运行的程序。它实际上是一个命令解释器,类似于dos中的command,它通常放在/bin目录下,由第2部分可以知道,shell有许多版本,用户可以根据个人喜好任选一种,前提是该shell程序必须存在于系统中。
  • 804. 11.7.2 shadow文件 用户账号的口令对系统的安全至关重要,/etc/shadow文件中就保存了所有系统用户口令的加密信息。只要得到了文件,在internet上随便找一个密码破解程序就能找出相当一部分用户的密码。另外,paasswd对一般用户是可读的,如果加密后的密码信息放在该文件中,则系统中的每个用户都可以读到加密后的口令。以前由于硬件速度的限制,试图破解一个精心选择的口令几乎是不可能的,而随着硬件技术的不断发展,以及网络功能的充分利用,一般的加密算法已经不能保证密码的安全性了,所以才产生了shadow技术,即将加密后的口令放在shadow文件中,而在passwd中相应的位置只放
  • 805. 一个“x”。shadow只对超级用户是可读的,一般用户无法读取。 下面我们列出一个典型的shadow文件的一部分: root:y9e2Gzjq/MCCc:11145:0:99999:7::: bin:*:11145:0:99999:7::: daemon:*:11145:0:99999:7::: adm:*:11145:0:99999:7::: lp:*:11145:0:99999:7::: sync:*:11145:0:99999:7::: shutdown:*:11145:0:99999:7::: halt:*:11145:0:99999:7::: mail:*:11145:0:99999:7::: news:*:11145:0:99999:7:::
  • 806. uucp:*:11145:0:99999:7::: operator:*:11145:0:99999:7::: games:*:11145:0:99999:7::: gopher:*:11145:0:99999:7::: ftp:*:11145:0:99999:7::: nobody:*:11145:0:99999:7::: gdm:!!:11145:0:99999:7::: postgres:!!:11145:0:99999:7::: squid:!!:11145:0:99999:7::: cheng:$1$PwqdIiQ0$vBYHwbSA/Mt31OICCwSrI/:11242:0:99999:7:::
  • 807. /etc/shadow文件包含了用户口令的加密信息,以及口令的有效期信息,每个用户占一条记录,每条记录9个域,依次定义如下: (1) 登录账号 (2) 加密口令,“*”或其他符号表示不能用来登录。 (3) 口令上次更改时间与1970年1月1日相隔的天数 (4) 口令更改后不可以再次更改的天数,0表示可以随时更改 (5) 口令的有效期,即口令更改后必须再次更改的天数,99999表示未设有效期 (6) 口令失效前警告用户的天数 (7) 口令失效后距账号被查封的天数,默认值-1 (8) 账号被封时距1970年1月1日的天数,默认值-1 (9) 保留未用
  • 808. 其中,加密口令域不能为空,否则用户不用密码即可登录,包括系统账号在内。口令长度随加密算法的不同而不同,一般它由13个有效字符组成。口令长度、有效日期等条件在“/etc/login.defs”文件中设置。 11.7.3 group文件 系统用户要查看自己所处的组,或者管理员要为某个用户增加一个组权限,都需要修改/etc/group文件的内容,该文件的例子如下: root::0:root bin::1:root,bin,daemon daemon::2:root,bin,daemon sys::3:root,bin,adm
  • 809. adm::4:root,adm,daemon popusers:x:231: slipusers:x:232: postgres:x:233: slocate:x:21: squid:x:101: utmp:x:234: cheng::500:cheng 在/etc/group文件中,每个组的信息占有一行记录,每个记录包括四个域,其格式如下: 组名:组访问密码:组标识符GID:用户名列表(用户名间以“,”分隔)
  • 810. 其中组访问密码域不经常使用,一般用“*”或其他字符填充,这时就只能通过修改/etc/group文件达到目的,可以在相应的组下添加该用户名。如果系统提供了组加密的工具软件包提供组密码,将出现加密的密文。 如果密码错误或不允许组访问,运行newgrp命令后,就会得到一个“permission denied”的错误信息。如果运行成功,则启动一个具有该组GID的shell,结束任务后,用户可以用exit或者不带参数的newgrp命令退出到原来的shell环境。 由于用户登录时,系统从/etc/passwd文件中取GID,而不是从/etc/group中取GID,所以group文件和passwd文件应当具有一致性。
  • 811. 11.8 小结 Linux在很大程度上是出于学习和爱好而装备的个人系统,一般只有机主使用,这种情况下,对账号管理是没有什么要求的,但是一旦系统由多人使用,作为系统管理员,就必须保证系统的可靠运行和正常服务。 本章中对用户账号的管理重点放在对超级用户和普通用户的讲解上,从安全角度上讲,作为系统管理员,一定要提防系统账号出现的漏洞,要经常关注安全方面的信息,及时打好补丁程序。另外本章中出现的命令也没有详细地说明,因为查看命令是手册所应该提供的功能,读者完全可以用man命令查看在线文档获得更为详细的命令信息。
  • 812. 另外在本章中没有提到的图形界面工具,如userconf、linuxconf等,这些工具的使用留给读者自己解决。
  • 813. 习题 11-1 不使用useradd命令,请直接通过修改账号配置文件达到添加、删除、禁用用户账号的目的。用户账号名可以任意选择(注意:实验机上操作完成后应该清理自己的工作)。 11-2 使用图形化界面工具userconf和linuxconf配置用户账号。 11-3 试着在不使用chfn命令时修改用户的私人信息,并用finger命令查看修改的用户信息正确与否。
  • 814. 第12章 文件系统维护12.1 Linux的目录构造 12.2 了解文件系统的使用情况 12.3 如何安装和拆卸文件系统 12.4 如何创建、修复和格式化文件系统 12.5 如何限制普通用户的使用空间 12.6 小结 习题
  • 815. 文件系统用于表示和组织系统的存储资源。对多用户操作系统而言,用户频繁碰到的问题是磁盘空间或者文件系统溢出的情况。还有一些例外情况导致空间不足,所以作为系统管理员必须要监督和管理用户的行为,保护好重要的磁盘分区。 Linux系统中所有的信息都组织成文件的形式,存储在一个以“/”为根节点的目录树中。本章介绍文件系统的维护,包括安装、拆卸、创建、恢复和格式化文件系统等内容。
  • 816. 12.1 Linux的目录构造 Linux与UNIX相比,其文件系统的结构有很多改动,尽管在目录内容上有很多相似。本节将讲解Linux文件系统的目录构造,让读者熟悉它们,而不是随意去更改它们。 Linux文件系统的目录结构以及各目录的功能如下: / 这是Linux系统的根目录。Linux不像DOS一样有C:D:E:等硬盘标识符,Linux是由根目录开始拥有一大堆子目录,而某个硬盘分区可能只安装在某个子目录上面,这些挂上另一个分区的子目录称为安装点。 /boot Linux系统开机信息,其中有系统启动时要安装的内核和模块信息。
  • 817. /bin 这是在单用户及多用户模式下都要用到的一般用户命令,这些命令都是开机时所必备的。 /dev 这是设备节点文件,包括块设备和字符设备,其中的块设备节点文件可以安装到文件系统的某个空目录下, ,该目录下有一个特殊的文件/dev/MAKEDEV,它是一个以root权限运行的可执行的应用程序,用来创建设备节点文件。 /etc 该目录下存放着系统启动和运行所需的配置文件和脚本文件,各种应用程序的配置文件和脚本文件,以及用户的密码文件、群组文件等。/etc/可以说是对系统最重要的目录,如果对某个文件不是绝对有把握,就不要尝试去改变它。
  • 818. /home 一般用户的主目录。 /lib 系统所需的函数库。 /mnt 通常这个目录是空的,通常情况下它就是我们所要用到的设备文件的安装点。 /sbin 这是在单用户及多用户模式下都用到的系统程序及管理命令,也是开机时所必备的。 /tmp 这是临时文件区,有许多程序都会建立临时文件,因此这个目录是绝对必要的。 /usr 这是包含大部分的用户命令以及应用程序的目录。 /usr/bin 一般用户命令、程序编辑器及应用软件。 /usr/games 一些文本模式的游戏。
  • 819. /usr/include 这是C语言的头文件,供程序开发使用。 /usr/lib 系统的函数库。 /usr/libexec 被其他程序调用执行的系统服务程序。 /usr/local 用来存放用户自己编译或安装的应用程序、资料文件、配置文件。读者最好将自己安装的软件装在该目录下。在/usr/local下也有/etc、/bin、/lib、/libexec等目录。 /usr/X11R6 X11R6(就是Xfree86)的所有程序、配置文件、头文件、字形、函数库等等。 /usr/sbin 可以让用户直接执行的系统守护程序(daemon),以及系统工具。 /usr/share 系统软件的数据库。
  • 820. /usr/dict 英文词库。 /usr/doc 文件说明信息、使用手册、常见问题。 /usr/man 联机文档,就是man命令所看到的内容。 /usr/srcLinux 系统源程序代码。 /var 系统记录文件、临时文件、输出缓冲区。 /var/db 重要的系统资料文件。 /var/log 系统记录文件。 /var/spool/mail 用户信件暂存区。 /var/preserve 文件编辑意外终止暂时存放。 /var/run 文件内容为正在执行的程序进程号,以“.pid”为后缀。
  • 821. /var/spool/mqueue 待发送或者接收中转的邮件暂存区,以队列方式等候处理。 /var/spool/lpd 打印机的资料暂存区。 /var/spool/uucp/uucpuucp 资料暂存区。 /var/spool/uucppublic 这是一般的uucp资料暂存区。 /var/tmp 系统暂存区,重新开机时不会被清除。 /var/yp YP/NIS的配置区。 如果读者还想对目录构造有更深入的了解,可以执行以下命令: # man hier
  • 822. 12.2 了解文件系统的使用情况 要管理文件系统,必须非常清楚文件系统的使用情况,Linux下提供了一些有用的工具,它们由GNU开发,和UNIX系统上的对应工具具有相似或相同的名字和功能,遵从POSIX可移植性标准。 1. df命令 该命令统计文件系统的使用情况。不加参数时会显示所有本地安装成功或通过nfs远程安装成功的文件系统,其部分常用参数的含义规定如下: -a 以块数显示所有文件系统大小 -h 用易于阅读的方式显示文件系统的大小 -I 用索引节点的个数来显示文件系统的大小
  • 823. -k 用1KB大小的块数显示文件系统的大小 -l 仅限于本地文件系统 -T 显示文件系统的类型 --sync 返回结果前调用sync命令 我们从这个命令的返回结果中可以得到比结果本身更多的信息,因为默认情况下文件系统大小以块数显示,我们可以用“-k”参数指定显示,磁盘总容量就等于块数与块大小的乘积,根据两次显示的块数就可以得到默认块大小。 df命令典型的输出结果显示格式如下: # df -kaTh Filesystem Type Size Used Avail Capacity/Use% Mounted on /dev/hda2 ext2 1007M 83M 873M 9% /
  • 824. 参数含义如下: Filesystem 文件系统名 Type 文件系统类型 Size 以所指定大小为单位的总磁盘空间,默认块大小一般为1KB Used 该文件系统已经使用磁盘空间大小 Avail 该文件系统未使用的磁盘空间大小 Capacity/Use% 该文件系统已使用空间的比例 Mounted on 安装点目录
  • 825. 2. du命令 du命令统计每一目录的磁盘利用率。该命令可以逐级进入每一个子目录并显示该目录的磁盘利用率,其部分参数含义规定如下: -a 统计指定目录下的所有目录及文件的块数 -s 只产生一个总的统计信息 -h 用易于阅读的方式显示文件系统的大小 -k 指定块大小为1KB -L 不计算符号连接 -m 指定以块大小为1MB的方式显示
  • 826. 12.3如何安装和拆卸文件系统 12.3.1文件系统的配置信息 Linux中,任何文件系统都是通过安装后才进行工作的。系统在引导时会按只读方式安装根文件系统,这使系统可以安装内核以及读取一些重要的启动文件,一般情况下,系统在启动时读取/etc/fstab文件并自动安装文件系统,fstab文件中描述了每个文件系统安装在何处以及管理员执行mount命令时所使用的参数,每条记录对应一个文件系统。 fstab文件中每条记录的格式如下: /device /mountpoint fstype parameters fs-freq fs-passno各项参数含义如下:
  • 827. /device 为需要安装的设备,如/dev/hda1。 /mountpoint 为该文件系统的安装点。 fstype 文件系统的类型。 parameters mount命令“-o”选项后面使用的参数。 fs-freq 由dump程序决定是否备份该文件系统,1表示要,0与空白表示不要。 fs-passno 由fsck程序决定引导时检查磁盘的顺序,首先它会依次检查该列值为1的文件系统,然后同时检查值为2的文件系统,0表示不检查。 # 表示注释性的内容,跟空行一样被省略。
  • 828. 12.3.2 特殊的文件系统 Linux中,除了ext2文件系统外,还有两个特殊的文件系统,即swap和proc文件系统。swap分区主要是用来作为虚拟内存使用,将内存长时间不使用的内容交换到swap分区上。如果系统内存很多,swap分区的作用就不大,因为Linux会自动把空余的内存作为高速缓存使用。Linux系统不使用mount命令安装swap分区,为了安装swap分区,必须在文件/etc/rc.d/rc.sysinit中加入对应的项,该项中应指定相应的命令(swapon),并使用“-a”选项指定安装swap的位置。 swap分区的信息可以从/proc/meminfo文件中得到,例如:
  • 829. # cat/proc/meminfo total: used: free: shared: buffers: cached: Mem: 129114112 120512512 8601600 77832192 63815680 20652032 Swap: 268869632 1638400 267231232 MemTotal: 126088 kB MemFree: 8400 kB MemShared: 76008 kB Buffers: 62320 kB Cached: 20168 kB SwapTotal: 262568 kB SwapFree: 260968 kB
  • 830. free、top等也可以查看swap分区的信息。 /proc是另一个特别的文件系统,它本身并不是真正的文件系统,不占用任何磁盘空间,也不用来储存文件,事实上/proc是Linux系统内核跟外界程序沟通的一个通道,我们称之为“伪文件系统”。/proc目录中的文件包含了大量内核的数据信息,其中大部分是只读的,有些对应到系统状态,有些对应到硬件或内存的内容,这些信息对了解系统状态大有帮助,有时候还可以在这里直接写入数据来配置系统。说明请参考/usr/src/linux/Documentation/proc.txt。 /proc中有许多以阿拉伯数字命名的目录,代表在内存中执行的程序,这些数字实际上就是程序的PID,例如要查看inetd进程的数据,可以使用下面的命令:
  • 831. # cat/var/run/inetd.pid(通过该命令获取inetd进程的PID) 510 # cat/proc/510/status(510对应目录即为inetd进程的信息) Name: inetd State: S(sleeping) Pid: 510 PPid: 1 Uid: 0 0 0 0 Gid: 0 0 0 0 Groups: 0 VmSize: 3576 kB VmLck: 0 kB VmRSS: 800 kB VmData: 64 kB VmStk: 24 kB VmExe: 32 kB
  • 832. VmLib: 1336 kB SigPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 8000000000001000 SigCgt: 0000000000086003 CapInh: 00000000fffffeff CapPrm: 00000000fffffeff CapEff: 00000000fffffeff 该目录下还有一些其他的文件和目录,如: /proc/ide 关于系统IDE设备的信息 /proc/net 关于系统网络设备的信息 /proc/scsi 关于系统SCSI设备的信息 /proc/parport 关于系统打印机端口的信息 /proc/sys/ 这个目录中放置了系统目前的配置状态,系统管理员可以用直接写入的方式配置系统,
  • 833. 例如/proc/sys/net/ipv4/目录下存放了关于网络的配置值,其中/proc/sys/net/ipv4/ip-forward这个文件控制了是否转发经过系统的数据包,在作为网关的主机上,这个转发功能是打开的,一般主机则没有打开的必要,要打开这个功能的指令是: # echo ″1″ >/proc/sys/net/ipv4/ip-forward 熟悉/proc文件系统会让你对Linux的了解突飞猛进,这里面也隐藏了许多非常有用的高级技巧,有心对Linux深入了解的读者可以参考文档说明,以掌握这个文件系统的奥秘,除了要阅读在线文档外,还要仔细阅读/usr/src/linux/Documentation目录下的文档。
  • 834. 12.3.3 如何用命令安装和拆卸文件系统 安装和拆卸文件系统常用两个命令mount和umount。mount命令的格式如下: # mount 命令参数 -t文件系统类型 -o可选参数/device /mountpoint 常用的命令参数有: -n 该参数表示不要更新/etc/fstab文件,这在启动脚本/etc/rc.d/rc.sysinit中非常有用,因为根文件系统为只读状态,无法写入/etc目录中的配置文件。 -r 以只读方式安装文件系统,相当于ro。 -w 以可读写方式安装文件系统,相当于rw。 -a 安装/etc/fstab文件中描述的所有文件系统。
  • 835. 可选参数有: auto 该选项一般与-a选项一起由启动脚本使用,表明应该安装此设备,于此选项相对的是noauto。 defaults 打开选项rw、suid、dev、exec、auto、nouser和async。 dev 允许使用系统上的设备节点,对设备的访问完全由对磁盘上设备节点的访问权决定,这是一个安全隐患,因此对可移动文件系统如软盘设备节点要采用nodev选项安装。 async 该选项以异步I/O方式保证程序继续执行,而不等待硬盘写操作,这可以大大加速磁盘操作,但是不可靠,与它相对的是sync。sync的特点是速度慢但比较可靠。
  • 836. exec 该选项通知内核允许程序在文件系统上运行,与它相对的是noexec,它告诉内核不允许程序在文件系统上运行,这通常用于安全防范措施。 user 允许普通用户安装和拆卸文件系统,出于安全方面的考虑,它包含nodev、noexec、nosuid等选项。所以如果suid参数后面跟着user参数的话,suid选项将被关闭。 suid 允许setuid、setgid位生效,出于安全考虑,常用nosuid。 ro 将文件系统设置为只读模式。 rw 将文件系统设置为可读/可写模式。 remount 该选项允许不中断mount命令为已经安装的文件系统改变特征。
  • 837. Linux支持的文件系统在/usr/src/linux/fs/filesystems.c文件中定义。mount命令在调用时,默认类型是iso9660,如果没有“-t”参数或者指定了auto选项,mount调用就会通过查找该文件系统的超级块来判 断文件系统的类型,如果失败,该命令将继续从/etc/filesystems文件中查找,如果该文件也不存在, 它就继续查找/proc/filesystems文件中的内容,除了 标识为“nodev”的特殊文件系统类型,其中所有的 文件系统类型都将被尝试。 /device必须是一个块设备,/mountpoint必须是一个 已经存在的目录,并且新安装的文件系统会暂时覆 盖安装点的文件系统,该目录下原来的文件将不可 读写,所以不能将文件系统挂接到根文件系统上。
  • 838. 当安装的文件系统不再使用时,可以使用umount命令将其从安装点拆卸下来,umount的命令常用格式如下: # umount 命令参数 /device 命令参数可以没有,但是如果安装时使用了“-n”,则此处一定也要带上,另外如果有不能拆卸的文件系统,如网络不通时的NFS文件系统,可以使用“-f”选项强行拆卸。
  • 839. 12.4 如何创建、修复和格式化文件系统 Linux硬盘的文件系统是在操作系统安装时创建的,因此在实际使用中我们常常需要对软盘格式化并为其创建文件系统。软盘驱动器对应的设备节点为/dev/fd,其中fd0表示第1个软驱,fd1表示第2个软驱,依此类推。 Linux提供了一个创建文件系统的命令mkfs,它可以用来在块设备上创建文件系统,该命令的格式如下: # mkfs -t文件系统类型 文件系统特定的选项 文件系统名 分配给该文件系统的块数 文件系统类型默认值为ext2,
  • 840. 文件系统特定的选项有: -c 创建之前检查设备的坏块 -v 产生详细的输出 软盘的格式化可以使用fdformat命令,对常用的3.5英寸软盘该命令的格式如下: # fdformat -n /dev/fd0H1440 “-n”表示格式化完毕不用做校验,如果对软盘没有信心还是不要带该选项的好。 软盘格式化之后应该使用mkfs在它上面创建一个文件系统,否则不能使用。因为Linux支持fat文件系统,所以Windows下或者DOS下制作的软盘不用格式化和创建新文件系统,可以直接安装到Linux文件系统中,其中的文件也可以操作。
  • 841. 有时候我们可能想为系统增加一些swap分区,这时候需要制作swap分区,比如要将/dev/hda3作为swap分区,可以按照下面的步骤进行: # mkswap /dev/hda3 # swapon /dev/hda3 然后在/etc/fstab文件中加入一行 /dev/hda3swapswapnodefaults00 Linux系统使用异步I/O方式访问硬盘。如果系统突然断电时会导致超级块索引节点的不一致,如果经常发生这种断电重启的事情,系统最终会崩溃。 注意文件系统的修复最好在单用户模式。除了fsck程序外,还有像e2fsck等程序可以用来检查和修复Linux文件系统。
  • 842. 12.5 如何限制普通用户的使用空间 12.5.1 quota的配置 “quota” 强制使用者占用的磁盘空间保持在他们的磁盘使用限额之下,取消他们在系统上无限制地使用磁盘空间的能力,这对于多用户系统非常有用。 quota可以从两方面指定磁盘的储存限制,按照使用者所能够支配的索引节点数量(也就是文件数目,除了有链接的情况)或者按照使用者可以取用的磁盘块数量。 quota是以每一使用者,每一文件系统为基础的,它不能跨文件系统对用户作出限制,如果使用者可能在超过一个以上的文件系统上建立文件,那么必须在每一文件系统上分别设定quota。
  • 843. 一般2.2以后的内核版本都支持磁盘限额的功能,低版本的内核可能需要重新编译,有时候升级内核也需要重新编译,在编译过程中需要加入quota的支持,另外需要编译并安装quota软件。安装了软件以后,需要修改系统的启动脚本文件“/etc/rc.d/rc.sysinit”以检查quota并且在启动期间打开quota,可以看该文件中的例子。要在该脚本中安装文件系统之后打开quota,否则quota不会运作。 还需要修改/etc/fstab文件的内容,在包含defaults的字段加上usrquota: /dev/hda3 /usr ext2 defaults,usrquota 1 1 如果需要在一文件系统中的群组quota支持,将usrquota改为grpquota
  • 844. /dev/hda3 /usr ext2 defaults, grpquota 1 1 如果要同时支持使用者quota与群组quota的话,则两者都加上。然后建立quota.user这个quota记录,以便通过quotacheck命令将用户的磁盘实用量填充到其中。quota.user应该由root拥有,且只有root有读写权限。按照以下步骤建立: # touch /partition/quota.user # touch /partition/quota.group # chmod 600 /partition/quota.user # chmod 600 /partition/quota.group 最后要重新启动系统以便让所作的更改生效,凡是涉及到对/etc/rc.d/rc.sysinit文件的修改一定要重新启动系统。
  • 845. 12.5.2 quota的使用 文件系统设置为支持限额控制后,就可以使用edquota命令为系统上某个普通用户设置限额了。该命令将进入vi(或是在$EDITOR环境变量中指定的任一编辑器),在每个启用quota的分区上为用户设置限额。该命令的格式如下: # edquota -u user Quotas for user bob: /dev/hda2: blocks in use: 2594, limits(soft = 5120,hard = 6400) inodes in use: 356,limits(soft = 1000,hard = 1500) blocks in use: 使用者在某个分区上已经使用的区块总数(以千字节为单位)
  • 846. inodes in use: 使用者在某个分区上所拥有的文件总数 edquota命令还可以为群组指定磁盘限额,使用“-g”参数。“-t”参数还可以设置用户可以超过软限额的时间。为了快速地为系统上的许多用户设置相同的限额值,可以先设置一个用户作为蓝本proto-user,然后按照下面的办法执行: # edquota -p proto-user user 还可以结合脚本批量执行,比如从/etc/passwd文件中对UID大于1000的所有用户执行相同的限额,可以编写下面的脚本: # edquota -p proto-user `awk -F: ′$3 > 1000 {print $1}′/etc/passwd`
  • 847. 注意′与`的区别,前者是允许变量的字符串,后者是要执行的命令。awk程序从文件中逐行读取用户的信息,第1个参数$1为用户名,第3个参数$3为UID。 在以上的叙述中,我们还要熟悉一些基本概念,如软限额、硬限额以及缓冲时间。软限额指quota使用者在分区上拥有的磁盘用量总数。硬限额只在设定有缓冲时间才运作。它指出磁盘用量的绝对限制,quota使用者不能超越这个限制。缓冲时间,就是由前面提及的edquota命令的“-t”参数所设定的,它是对quota使用者实行软限额之前的时间限制。可以使用的时间单位是秒、分、小时、日、星期、以及月。
  • 848. 12.5.3 其他的quota命令 1. quotacheck 用来扫描文件系统的磁盘用量,并更新“quota.user”,使quota记录保持最新的状态。可用cron定期执行quotacheck或在每次系统启动时执行。 2. repquota 产生文件系统的quota信息。它的输出格式如下: # repquota -a Block limits File limits User used soft hard grace used soft hard grace 3. quotaon以及quotaoff quotaon是用来打开quota的计算,quotaoff则是将其关闭。它们是在系统启动与关机时执行的。
  • 849. 12.6 小结 本章中我们学习了如何操作文件系统,包括了解文件系统的使用情况、如何安装和拆卸文件系统、如何创建、恢复和格式化文件系统,如何为用户设定磁盘限额以及Linux文件系统的结构。文件系统是内核与人之间的一个界面,它作为内核的一个关键部分,是我们了解内核工作机理的一面镜子。内核模块的其他3大部分(进程调度、I/O与存储管理)都依赖于文件系统而工作,即使新的微内核设计思想把文件系统作为单独的模块,独立运行于内核空间之外,也丝毫没有降低文件系统在操作系统中的特殊作用。
  • 850. 习题 12-1 从网上下载一个iso文件,试着用mount光驱类似的办法加载该文件系统。 12-2 试着利用quota为普通用户配置限额。 12-3 查找资料,在已设置了一个分区作为交换区的情况下,使用一个文件替代原先设置的交换分区,从而释放原先交换分区的空间。
  • 851. 第13章 TCP/IP网络管理13.1 网络概述 13.2 网络配置 13.3 定为基本的网络故障和收集网络状态信息 13.4 基本网络服务的介绍 13.5 小结 习题
  • 852. 主机系统的网络管理涵盖很多方面的内容,包括网络设备的安装、网络故障的检测、网络流量的统计以及状态信息的收集,本章将通过一些基本网络操作命令的介绍和对网络配置文件的分析,帮助读者更好地理解网络的工作原理,提高管理技能。
  • 853. 13.1网络概述 Linux是一个网络操作系统,系统管理的很大一部分工作与网络有关。和传统的Unix一样,Linux中,也同时支持TCP/IP网络和UUCP网络。UUCP(Unix-to-Unix Copy)是由美国贝尔实验室开发的、供UNIX工作站之间进行通信的一套协议簇,它主要是通过拨号电话线路进行通信,尽管UUCP网络仍然广泛地应用于各种场合,而且费用低廉,但它有限的传输带宽将制约它的发展。随着TCP/IP网络的迅速发展,可以预见UUCP的应用范围将不断地被削减。本章主要介绍TCP/IP网络的管理,不再对UUCP进行过多的讨论。有兴趣的读者可以通过其他途径深入了解。下面将结合TCP/IP网络在Linux中的实现介绍一些基本概念。
  • 854. TCP/IP被称为一种事实上的Internet互联标准,因为它并不完全遵从ISO/OSI标准,但是因为Internet是从TCP/IP协议基础上发展起来的,在标准委员会制定出标准时,TCP/IP已经得到了广泛的应用和厂商支持。人们最终抛弃了政府行为,而选择了在市场需求中茁壮成长起来的TCP/IP标准,这一点在计算机界常常得到印证。 图13.1是TCP/IP协议簇的原理结构图,它反映了网络系统的工作原理。
  • 855. 图13.1 TCP/IP协议簇的结构图
  • 856. TCP/IP协议簇的核心部分包括传输层协议(TCP和UDP)、网络层协议(IP)和硬件接口层,这三层在操作系统内核中实现。而应用层如FTP、WWW等应用程序则通过网络编程接口(socket、Windows Sockets)与核心协议打交道。整个协议簇是一种分层结构的,下层为上层提供服务,不同层次之间通过一些接口通信,比如应用层通过socket接口与TCP层通信。 将通信功能分层可以简化各层的实现,优化每一层的功能,达到代码重用、最小修改和易于维护的目的。模块化在软件设计与实现中无论是面向对象技术还是分布式处理都有其不可替代的优越性,是软件工程的理想目标。采用这种层次性的结构还可以
  • 857. 灵活地配置网络,可以通过为硬件驱动规定统一的接口,将硬件的运作和处理交给不同的生产厂商去做。最终的好处是无论采用什么样的硬件环境,都可以通过TCP/IP网络达到互联的要求。下面将结合最为常见的以太网进行分析。
  • 858. 13.2 网络配置 13.2.1 以太网卡的安装 我们常用的网卡有两种总线模式,一种是ISA卡,一种是PCI卡。PCI卡比ISA有许多优点,除了提供很高的总线带宽来达到更快更好的性能外,它对系统资源的申请是动态的,而ISA必须固定分配。典型的情况就是装载ISA卡时,Linux需要给它分配一个中断号和I/O资源的地址,以便驱动程序知道在何处可以找到该卡。 系统加载网卡也有两种模式,一种是直接编译进内核,一种是动态加载模块。若设备驱动以模块方式动态加载进内核,对于PCI设备,模块将自动检测到所有已经安装到系统上的设备;对于ISA卡,则
  • 859. 需要向模块提供I/O地址,这些信息应在/etc/conf.modules中提供(有的系统为modules.conf)。比如有一块ISA总线的3c509卡,编辑conf.modules文件如下:alias eth0 3c509 options 3c509 io=0x300这样驱动程序就知道到内存的哪一段去寻找网卡,其中0x表示16进制。对于PCI卡,仅仅需要alias命令来使设备名(以太网设备为ethN)和适当的驱动模块名关联即可,PCI卡的I/O地址将会被自动检测到。对于PCI卡,编辑conf.modules文件如下:alias eth0 3c509注: 加载模块的命令格式如下:# insmod 模块名(本例中为3c509)若驱动程序直接被编译进了内核,系统启动时的PCI检测程序将会自动找到所有相关的网卡。ISA卡一般也能够被自动检测到,但是在某些情况
  • 860. 下,ISA卡仍然需要做下面的配置工作,在/etc/lilo.conf中增加配置信息,其方法是通过LILO程序将启动参数信息传递给内核。对于ISA卡,编辑lilo.conf文件,增加如下内容:append=″ether=3,0x300,eth0″ 注: 先不要在“lilo.conf”中加入启动参数,测试一下你的ISA卡,若失败再使用启动参数,有些旧的ISA网卡,必须使用其驱动盘设置中断号与I/O地址或者采用硬跳线改变中断号,在系统中配置的参数无效。PCI卡会被自动查找到,所以没有必要这样做。
  • 861. 13.2.2 TCP/IP网络相关的概念 前面提到了TCP/IP网络的结构以及如何加载硬件驱动程序,剩下的工作就是如何在系统中配置TCP/IP,以使其能正常工作。在开始讲配置之前,必须澄清一些基本概念,以让读者理解为什么要这样配置。 1. IP地址 TCP/IP网络要进行通讯,必须有一个标识主机的方法。在以太网中,可以通过网卡的硬件地址来标识主机,但是这种地址格式复杂,不便于阅读和记忆,也不便于管理。所以TCP/IP网络中定义了一种地址格式,用来惟一确定每个网络接口。它具有如下格式:
  • 862. X.Y.Z.W 其中X、Y、Z、W是0到255之间的整数,如果按照二进制的书写格式,它是一个32位的数字,对于TCP/IP协议簇来说,它所认识的IP地址与上面的格式有点不同,它以如下格式阅读: 网络地址+主机地址其中网络地址是大于1位的二进制数,主机地址也是大于1位的二进制数。比如,计算中心网关地址166.111.4.1分解成协议所能认识的地址就是: 网络地址=1010011001101111 主机地址=0000010000000001
  • 863. 后面将介绍为什么这样分解。需要注意的是,在IP地址中,全0主机地址代表的是网络,全1主机地址代表的是广播。比如对IP地址166.111.4.1而言,它所在的网络用166.111.4.0来表示,而166.111.4.255则代表向整个166.111.4网络广播的地址。 以上的设计贯彻了灵活的原则,给IP地址带来了很好的实用性。我们可以根据某个机器的数目给不同的单位分配不同的网段,于是就诞生了IP地址分类的问题。举个例子来说,像166.111网段可以拥有的主机数可以用16位主机地址表示,即可以达到65536台主机,所以像清华大学这样的单位,拥有一个像166.111这样的网段是合适的。而对于大型
  • 864. 的跨国公司如IBM,则可能拥有上十万台的主机,16位主机地址是不能满足要求的,可以分配一个24位的主机地址。而对一些小公司而言,可能分配一个拥有255台主机数的8位主机地址的网段就可以满足要求了。 最大主机数[]16777214[]65543[]254[]N/A[]N/A最大主机数比理论数目少2个,是因为网络地址和广播地址是保留地址。另外,有一些地址是保留用于特定的内部网络的,这些网络没有直接连接到Internet,它们可能放在防火墙后面,这些地址规定如下:
  • 865. A类: 10.0.0.0 B类: 172.16.0.0到172.31.0.0 C类: 192.168.0.0到192.168.255.0 IP地址经过分类,确实方便了记忆和管理,但是也造成了地址的浪费,许多地址即使空着,但归属某个单位或部门,别人没有办法使用,从而造成了地址空间的紧张,当然这也在很大程度上是因为32的地址空间限制。所以Ipv6(目前的IP协议版本为Ipv4)技术的一部分工作就是解决地址空间不足的问题。
  • 866. 2. MAC地址 MAC地址在以太网中是网卡的硬件地址,以太网中机器之间通过这个地址通信,它是一个6字节48位的数字,其常见格式以十六进制数字表示如下:xx:xx:xx:xx:xx:xx可以通过ifconfig命令来查看它。在IBM的令牌环网中也有硬件地址的概念,但两者有很大的区别,在同一本地网络中,如果要让这种硬件地址格式不同的网络互连,必须通过专用的设备,如网桥等。我们所说的TCP/IP网络是由许多小的网络构成,这些网络可能是以太网也可能是令牌环网,TCP/IP协议通过一个地址转换协议ARP来映射IP地址与硬件地址的对应关系。同一本地网络中,硬件地址必须惟一,因为它是区分不同主机
  • 867. 的惟一标准。以太网中通过ARP地址广播包来收集其他主机的地址。 3. 子网掩码 操作系统中,TCP/IP协议簇在工作时,将IP地址看作是网络地址与主机地址的聚合体,其中网络地址是用来确定数据包的传输路径的,比如如何将一个数据包从美国UC-berkely大学的校园网发送到清华大学的校园网。在这个发送过程中,路由协议根据网络地址确定数据包从哪个路由器发送到下一个网络。而对于子网掩码而言,它是用来确定这个网络地址的,将子网掩码值与主机的IP地址做按位“与”运算,就得到了网络地址,从而也就决定了该机器上的数据包按照什么样的路径发送给别人,按
  • 868. 行话说,就是影响了主机的静态路由。举例说,主机A:192.168.2.4与B:192.168.2.5的子网掩码都为255.255.255.0,192.168.2.1为网关,如果主机A要发送信息给B,它通过子网掩码发现B与它处在同一网络,于是就将数据包直接发送给该机器,但是如果将主机B放在网关以外,因为以太网的ARP广播包不能通过路由器,得不到对方的MAC地址,从而主机A无法知道B不在本网段这一信息,所以不会去寻找网关转发该数据包,通信也就无法进行。这可以解释对于将子网掩码设大了或设小了所导致的种种问题。
  • 869. 所以遇到这种问题,一定要明白,子网掩码将决定你机器上的信息是怎么传送给别人的,如果在同一网段,它绝对不会主动找网关,只有不同网段的机器才会通过网关路由。 根据子网掩码的工作原理,还可以设计可变长度子网掩码VLSM,从而可以将大的网段划分成小的网段,也可以用小的网段构建大的网段(超网),不同的单位可以根据需要自行决定采用什么方式工作。
  • 870. 13.2.3 和网络相关的一些配置文件 在Linux系统中,TCP/IP网络是通过若干个文本文件进行配置的,了解这些配置文件对于理解一些配置命令和界面配置工具大有好处。你可以通过编辑这些文件来完成联网工作。下面将介绍基本的TCP/IP配置文件。 1. /etc/HOSTNAME文件 该文件包含了系统的主机名称和完全的域名,如:linux.cic.tsinghua.edu.cn(Linux为主机名,cic.tinsghua.edu.cn为域名)
  • 871. 2. /etc/sysconfig/network-scripts/ifcfg-ethN文件 在RedHat中,系统网络设备的配置文件保存在/etc/sysconfig/network-scripts目录下,ifcfg-eth0包含第一块网卡的配置信息,ifcfg-eht1包含第二块网卡的配置信息。 下面是/etc/sysconfig/network-scripts/ifcfg-eth0文件的示例:DEVICE=″eth0″表示物理设备的名字 IPADDR=″192.168.2.1″表示赋给该卡的IP地址 NETMASK=″255.255.255.0″表示网络掩码 NETWORK=″192.168.2.0″表示网络地址 BROADCAST=″192.168.2.255″表示广播地址
  • 872. ONBOOT=″yes″启动时是否激活该卡,值为yes/no BOOTPROTO=″none″proto取值可以是: (1) none: 无须启动协议 (2) bootp: 使用bootp协议 (3) dhcp: 使用dhcp协议 USERCTL=″no″是否允许非root用户控制该设备,值为yes/no 若希望手工修改网络地址或在新的接口上增加新的网络界面,可以通过创建新的文件,文件名为ifcfg-ethN,N为0、1等数字。
  • 873. 3. /etc/resolv.conf文件 该文件是由DNS客户端解析器(resolver,一个根据主机名解析IP地址的库)使用的配置文件,示例如下: search cic.tsinghua.edu.cn nameserver 166.111.4.5 nameserver 166.111.8.28 “search域名”表示当提供了一个不包括完全域名的主机名时,在该主机名后添加域名后缀;“nameserver”表示解析域名时使用该地址指定的主机为域名服务器。其中域名服务器是按照文件中出现的顺序来查询的。
  • 874. 4. /etc/host.conf文件 该文件指定如何解析主机名。Linux通过解析器库来获得主机名对应的IP地址。示例如下: order bind,hosts multi on nospoof on “order bind,hosts”指定主机名查询顺序,这里规定先使用DNS来解析域名,然后再查询“/etc/hosts”文件。 “multi on”表示“/etc/hosts”文件中指定的主机可以有多个地址,拥有多个IP地址的主机一般称为具有多个网络接口。
  • 875. “nospoof on”指不允许对该服务器进行IP地址欺骗。IP欺骗是一种攻击系统安全的手段,通过把IP地址伪装成别的计算机,来取得其他计算机的信任。 5. /etc/sysconfig/network文件 该文件用来指定服务器上的网络配置信息,下面是一个示例: NETWORK=yes/no网络是否被配置 FORWARD-IPV4=yes/no是否开启IP转发功能 HOSTNAME=Air表示服务器的主机名 DOMAINNAME=cic.tsinghua.edu.cn分配给该机器的域名,这个字段基本不用 GATEWAY=166.111.4.1表示网络网关的IP地址 GATEWAYDEV=eth0表示网关的设备名
  • 876. 注意,因为不同版本的系统或者不同的应用软件会从不同的地方去取主机名,为了保证同一个系统的所有应用程序采用的是相同的主机名,应保持HOSTNAME文件与该文件中的主机名一致。 6. /etc/hosts文件 当机器启动时,在可以查询DNS以前,机器需要查询一些主机名到IP地址的匹配。这些匹配信息存放在/etc/hosts文件中。在没有域名服务器情况下,系统上的所有网络程序都通过查询该文件来解析对应于某个主机名的IP地址。
  • 877. 下面是/etc/hosts文件的示例: 127.0.0.1 localhost localhost.localdomain 202.112.58.200 smthbbs 166.111.4.6 rs6000 rs6000.cic.tsinghua.edu.cn 最左边一列是主机IP信息,中间一列是主机名,任何后面的列都是该主机的别名。一旦配置完机器的网络配置文件,应该重新启动网络以使修改生效。使用下面的命令来重新启动网#/etc/rc.d/init.d/network restart Stopping network: [OK] Starting network: [OK] 注意,Linux/UNIX中,因为有权限限制,所以路径不是对所有用户都开放的,所以许多路径在用户
  • 878. 的环境变量中是找不到的。任何用户都有自己的PATH环境变量,不同用户可能设置得不一样,从而有“路径不是对所有用户都开放”的假象。另外,超级用户的PATH环境变量中不应该有当前路径“.”,这是从安全方面考虑的要求,因此超级用户执行当前目录下某个命令时,可能要在命令名前加上“./”。试想一下,某个捣蛋的用户编写了一个恶意的程序,并将它命名为rm,放置在自己的命令下,然后告诉管理员说自己目录下有一个文件(譬如说文件名为“ls -l”,注意中间有一空格)怎么也删不掉,粗心大意的管理员进入这个目录后,使用命令rm ″ls -l″一下子就删掉了,还对那位用户大谈UNIX中各种引号的作用,而那位用户却在那儿窃笑呢,因
  • 879. 为管理员执行的是他编写的同名程序,而该程序表 面上完成/bin/rm程序的功能,实际上却留下一个后门,比如拷贝一个root的shell并加上粘贴位,他以后就可以随心所欲地取得超级用户特权。所以在执行命令时,最好给出绝对路径,如在在当前目录中,则应该加上“./”,如当前目录/etc/rc.d/init.d下执行上述命令的格式应该为:# ./network restart不过在此处提醒读者,涉及到网络配置文件的修改有时仅仅靠重新运行network脚本是不够的,最好同时运行rc.local脚本。
  • 880. 7. /etc/inetd. conf文件 inetd被称做因特网“超级服务器”,根据网络请求装入相应的网络程序,inetd.conf文件告诉inetd应该监听哪些端口,为每个端口启动哪些服务。因为这个配置文件决定了系统的服务内容,所以也存在潜在的安全威胁,最好的办法就是禁止所有不用的服务。注意,任何对该配置文件的改动都必须让inetd重新读入配置文件,这可以通过kill命令给inetd进程发送一个挂起信号(HUP)达到目的,因为许多系统守护进程接收到这个信号后会重新读入自己的配置文件。命令的格式如下: # kill-HUP `cat/var/run/inetd.pid`
  • 881. 注意:HUP信号为1,inetd的PID在Linux中存放在“/var/run/inetd.pid”文件中。 不过不建议初学者改动这个配置文件,如果有不用的服务,删除相应的软件包更为可靠。 13.2.4用命令行方式配置TCP/IP网络 1. ifconfig命令 ifconfig是用来设置和配置网卡的命令行工具,为了手工配置网络你需要熟悉这个命令。同Windows相比,Linux/UNIX下配置工作的好处是无须重新启动机器。下面将通过示例的形式讲解。
  • 882. 例: 为eth0配置IP地址,命令格式如下: # ifconfig eth0 192.168.2.4 netmask 255.255.255.0 这条命令自动指定了广播地址,网络地址可以通过IP地址与子网掩码按位“与”获得,主机地址全为“1”,所以得到广播地址为192.168.2.255。也可直接写出广播地址: # ifconfig eth0 192.168.2.4 netmask 255.255.255.0 broadcast 192.168.2.255 若运行不带任何参数的ifconfig命令,这个命令将显示机器所有激活的接口的信息,例如: # ifconfig这个命令的输出如表13.2所示。
  • 883. 表13.2不带参数的ifconfig命令的输出结果(Alpha工作站) 注意: 用ifconfig命令配置的网络设备参数,在重新启动以后,这些参数设置将会丢失Eth0Link encap:Ethernet HWaddr 00:50:DA:8E:2A:5E inet addr:192.168.2.4 Bcast:192.168.2.255 Mask:255.255.252.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:6323740 errors:0 dropped:0 overruns:0 frame:0 TX packets:30708 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 Interrupt:5(注:Intel平台一般会显示I/O地址)LoLink encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:8020 Metric:1 RX packets:368 errors:0 dropped:0 overruns:0 frame:0 TX packets:368 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 collisions:0 txqueuelen:0
  • 884. 表中数据的含义如下: eth0: 当前网卡的名称 Link encap:表明网卡被设置为以太网卡,有些系统还能给出带宽参数 Hwaddr: 网卡的硬件地址(MAC地址) Inet addr: 为该网卡配置的IP地址 Bcast: 广播地址 Mask: 子网掩码地址 第3行: 表明已经应用到网卡上的ifconfig命令的可选选项,有些是默认值。 第4、5行: RX、TX分别表示接收和发送的数据包的信息。
  • 885. Lo: 回送设备,一般用于设备的自测。 带有-a参数的该命令则显示所有的接口的信息,包括没有激活的接口(但是有些老版本的系统可能不能显示没有激活的接口),命令格式如下,输出内容和上面的相似。 # ifconfig-a ifconfig命令除了可以配置IP地址外,还可以配置硬件地址,如以太网卡的MAC地址,其他种类的硬件需要系统能够支持,比如要修改第一块网卡“eth0”的MAC地址,其实现方法是在文件“/etc/rc.d/init.d/network”中添加下面一行命令:ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
  • 886. 其中hw表示硬件地址,ether为网络类型,然后使用下面的命令重新激活网卡即可:#/etc/rc.d/init.d/network restart 注: 虽然用ifconfig命令设置的参数会在机器重新启动时丢失,我们也可以通过在启动网络的脚本文件中添加上这些命令,这样每次重启机器时系统都会执行到这些脚本文件,可以达到永久改变的目的。如果要永久改变IP地址,可改变“/etc/sysconfig/network-scripts/ifcfg-ethN”文件中IPADDR项的内容,如: IPADDR=“192.168.2.254”
  • 887. 2. route命令 route命令影响的是主机静态路由表,由管理员手工维护。对于一般主机而言,它可以告诉一台主机如何发送数据给其他主机。如果主机充当路由器,它还要负责在不同网络间转发数据。路由是在IP层进行的,当收到一个目的地为其他主机的报文后,本主机将其网络地址与路由表中的内容进行比较,如果目的地为直接相连的网络,则直接将报文发送至该网络;如果没有直接匹配的网络地址,则将报文发送给某个默认路由器,由它进一步路由报文;如果没有默认路由,将返回给发送端一个网络不可到达的错误信息。
  • 888. 除了由管理员手工修改路由表信息外,主机本身也可以收集RIP(Routing Information Protocol)路由广播或者其他IGP(Interior Gateway Routing Protocol)类路由协议的广播信息,生成动态路由信息。 在进一步介绍如何配置之前,让我们使用“route-n”命令输出路由表信息,来分析一下路由表的内容,“-n”参数的含义是不启用域名解析,只显示IP地址。 #/sbin/route-n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.4.5 0.0.0.0 255.255.255.255 UH 0 0 0 eth0 192.168.4. 0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 127.0.0.0 0.0.0.0 255. 0.0.0.0 U 0 0 0 lo 0.0.0.0 192.168.4. 0 0.0.0.0 UG 0 0 0 eth0
  • 889. Destination是数据包被传送到的目标网络或主机地址;Gateway是用来向目标发送数据包的网关(通常是一个路由器);Genmask是子网掩码;Metric提供的是此路由的权值,权值越小说明该路由越快,不过它只对动态路由有用,因此为0;Ref列描述这一路由的引用数,Linux内核中没有使用这条信息,因此其值为0;Use表示这条路由被系统引用的次数;Iface是此路由使用的网络接口,“*”表示没有设置网关;Flags用来描述路由的特征,可以是下面几个值: U此路由已经启动 H此路由的目标是一个主机 G此路由通过一个网关
  • 890. 上面已经对主机的路由表做了简单的介绍,下面就通过例子介绍如何操纵主机路由表,首先讲解如何使用route命令配置默认网关,命令格式如下: # route 命令参数 类型 目标主机或网络的 IP 子网掩码 网关 可选项 命令参数有添加路由“add”和删除路由“del”,使用add需要指明“类型”参数是“-net”还是“-host”,而使用del时无须指定。目标主机或网络的IP可以设置为“default”,即默认的网关。可选项参数可以为“-n”等,具体的信息请参考联机文档“man route”。例如要为目标主机“192.168.2.4”添加网关路由“192.168.2.1”,格式如下: # route add -host 192.168.2.4 netmask 255.255.255.0 gw 192.168.2.1
  • 891. 13.3 定位基本的网络故障和收集网络状态信息 ping命令 检查主机的连通性可以用ping命令,如果主机网络不通我们怎么办呢?在局域网内,我们可以先用该命令测试与相邻主机是否连通,如果否,则需要检查本机的网络配置和网线是否损坏。如果可以连通,则本机的网络没有问题,需要继续判断故障所在,可能是本地网络设备故障,也可能是外网引起的,需要和其他网络管理员协调。ping命令的格式如下: # ping 可选参数 目标主机的IP地址
  • 892. 这里的可选参数有很多,包括利用缓冲区溢出攻击用的“-l”选项,不过现在的操作系统已经弥补了这个漏洞。图13.1表明ping是利用ICMP工作的,ICMP定义了许多描述远方主机或者网络状态的信息,当远方主机或者路由器接收到ICMP请求包时,即用ICMP响应包返回这些信息。例如从“192.168.2.4”ping“192.168.2.1”,部分结果如下:
  • 893. # ping 192.168.2.1 PING 192.168.2.1(192.168.2.1) from 192.168.2.4 : 56(84) bytes of data. 64 bytes from 192.168.2.1: icmp-seq=0 ttl=30 time=2.1 ms 64 bytes from 192.168.2.1: icmp-seq=1 ttl=30 time=1.3 ms 64 bytes from 192.168.2.1: icmp-seq=2 ttl=30 time=0.6 ms 64 bytes from 192.168.2.1: icmp-seq=3 ttl=30 time=0.5 ms 64 bytes from 192.168.2.1: icmp-seq=4 ttl=30 time=0.7 ms 64 bytes from 192.168.2.1: icmp-seq=5 ttl=30 time=1.2 ms--- ---192.168.2.1 ping statistics ----- 6 packets transmitted,6 packets received,0% packet loss round-trip min/avg/max = 0.5/1.0/2.1 ms
  • 894. 2. traceroute命令 为了判断外网的工作情况,可以使用另一个非常有用的命令traceroute,以确定到远方主机的路由,也就是数据包发送到远方主机需要经过哪些路由器。有时候ping某个远方主机不通是因为某个路由器引起的,则可以通过该命令发现故障。我们可以用此命令验证前面关于“子网掩码影响主机路由”的说法,如果同在一个子网,则不需要经过网关,数据包直接发往该机器,如果是子网以外的机器,则第一步数据包发送给网关,然后由网关转发。如有以下网络拓扑,子网掩码均为255.255.255.0
  • 895. A网段主机a:192.168.2.4 从a到c只须一步即可,如: #/usr/sbin/traceroute 192.168.2.5 traceroute to c(192.168.2.5),30 hops max,46 byte packets 1 c(166.111.4.5) 0.372 ms 0.153 ms 0.187 ms A网段主c:192.168.2.5网关192.168.2.1B网段主机b:192.168.3.4
  • 896. 从a到b则需要经过网关,如: #/usr/sbin/traceroute 192.168.3.4 traceroute to b(192.168.3.4),30 hops max,46 byte packets 1 192.168.2.1(192.168.2.1) 3.596 ms 0.690 ms 0.947 ms 2 b(192.168.3.4) 2.489 ms * 2.823 ms 如果判断结果为本地网络工作正常,故障存在于本机的话,可以从网线到网卡逐步进行检测,另外要观察网卡信号灯的状态,信号灯的含义一般包括网线是否正常连接(绿灯)和是否有数据传输(红灯),如果信号灯有错,则硬件很可能有问题。一般来说,硬件的错误相对较少,而软件驱动的安装错误会多一些,所以安装系统时要对机器内部安装的硬件比较清楚。引起到本地主机网络故障的原因很多,
  • 897. 笔者的经验也绝对不能一一囊括,以上只是从总体上给出一个判断与解决的顺序,读者则需要从实践中积累经验,并与其他人多交流。 3. netstat命令 为了快速检查网络接口的状态信息,可以使用“netstat-i”命令 如果TX-ERR或RX-ERR数量过大,则往往表示网线有问题,TX-DROP和RX-DROP过大则表示网络负载较重,主机来不及处理,而TX-OVR和RX-OVR则可能因为速率不匹配引起。
  • 898. 另外“netstat-a-n”也可以显示主机的路由表,其作用相当于“route-n”。为了显示所有的TCP和UDP端口状态,包括活动的端口和不活动的等待连接的服务器端口(监听端口)。可以使用“netstat-a”命令。 netstat命令的另外一个有用处的选项是-t,它只显示所有的激活的TCP连接,从而过滤了所有UNIX domain sockets(本机通信协议)的连接,命令格式如下: # netstat-t 如果要显示所有的活动的和被监听的TCP连接,使用命令: # netstat-vat
  • 899. 13.4 基本网络服务的介绍 Unix/Linux系统自出世以来就是贵族出身,在很大程度上都是用于提供系统服务的,而且也因为它们出色的表现赢得了业界的赞许,尽管Linux现在还不能尽如人意,但是它自由开放的特征吸引了无数优秀的程序员和系统管理人员,正是这些勤劳无私的人们的不懈努力,Linux才得以普及和不断完善。 Linux在Web、DNS、Mail等等网络服务方面都有杰出的表现。它还可以做防火墙、路由器、代理服务器等,而且它还可以作为嵌入式系统应用于IA(信息家电)领域,可以作为VPN网关等。本书后续的教材中将对这些服务的架构、配置等进行详细的分析,在这里就算是抛转引玉,让读者对这些服务有一个基本的了解。
  • 900. 13.4.1 Web服务器 谈起Web服务器,最著名的就是Apache了,它可以说是目前市场上最流行的运行于Linux上的Web服务器,而且在NT上也有了它的身影,不过性能明显不能跟它在Linux上的表现那样让人乐道。 Web服务器是构建于HTTP协议上的应用程序,市场上有很多家的产品,除了Apache,还有如Webmin自带的miniserver等。他们在协议上都是兼容的,但是配置、功能乃至版本更新都是有很大差异的。一般Linux上的Web服务器提供虚拟主机的支持、代理的支持、还有PHP支持,一些外加的软件包还支持Linux上的ASP。正是随着Web服务器功能的不断强大,现在的网站才日趋规模,才能
  • 901. 结合大型数据库进行管理,才有丰富的内容展现给大家。要追踪Web的发展,Linux是一个非常好的平台。 13.4.2 邮件系统 自Eric Allman在Berkeley完成sendmail的最初版本以来,sendmail受到了业界长久的重视,从1983年的V5版本一直到1993年Eric重新改写的V8版本,都受到了人们的尊重,虽然它复杂的配置工作给管理员带来了不少的麻烦,但人们不得不赞叹它的灵巧。
  • 902. 邮件系统由3部分组成,用户代理(UA)是供用户阅读和编写邮件的,邮件传输代理(MTA)在主机间完成邮件的转发,投递代理(DA)则负责将邮件放入用户的信箱内。 除了sendmail外,还有一个POP系统。sendmail实际是邮件投递代理,它通过对信件头部信息的改写来控制在不同主机间的路由,而信件到用户信箱的投递工作则由POP服务器来完成。POP服务器还负责对用户进行身份认证以及信箱管理,它通过用户的邮件客户端与用户打交道。现在有许多可选的邮件系统,其中qmail在Linux上就有很好的名声,并且在同一个软件包里提供了对sendmail和POP的支持,读者可以进一步阅读相关资料获得更深入的了解。
  • 903. 13.4.3 域名服务器 当前应用最多的DNS服务器就是Bind版本,当前是Bind8版本。DNS提供了从名字到IP地址的映射关系,这种映射关系不必是一一映射,一个IP可以有多个域名,一个域名也可以对应多个IP。 DNS的诞生主要是为了解决NIS的不足,人们为了方便地记忆和标识主机,就给每个主机一个名字,早期的Internet规模较小,从名字到IP的映射关系通过一个集中的数据库管理,但随着Internet的迅速膨胀,重名的问题没办法解决,于是就诞生了域名系统,它通过分层管理与划分管理区域,保证每一个管理区域内部命名的惟一性,从而保证了整个Internet内主机名的惟一性。域名必须向专门的
  • 904. 机构申请才能获得,并且要遵循一定的原则才能正常工作。 一个好的网络系统,除了要有高效的DNS系统、可靠实用的邮件系统外,还需要防火墙系统,一个高效安全可靠的网络系统是系统管理员追求的目标。要在网络管理方面有更高的造诣,不仅需要经验,还需要锲而不舍的精神,尤其是网络安全,需要网络管理员不仅对网络系统非常了解,还要对主机系统(包括应用服务和操作系统)有很深入的了解。
  • 905. 13.5 小结 本章主要讨论了TCP/IP网络,实际上还有许多其他协议簇,如Novell公司的SPX/IPX协议簇,苹果公司应用于Machitosh机上的AppleTalk协议簇,DEC的DECNet协议簇(该协议簇体现了DEC公司为了赢得美国政府订购单所作的努力,它同时支持TCP与OSI)。不过TCP/IP无论现在还是将来都是网络世界的主流标准,其地位还在进一步地得到加强。 通过学习和阅读本章,应该熟练地使用基本的网络配置命令工具和网络状态检测工具,并了解这些命令工具的幕后操作,与它们相关的配置文件等。至于图形化的配置工具,相信在了解了这些内容后,读者能很轻松地驾驭它们。
  • 906. 对于基本的网络服务,不是本书的重点,本章只做了简单的介绍,本系列教材将会在网络服务部分详细讲述。
  • 907. 习题 13-1 TCP/IP协议簇分成哪四层?IP、TCP、FTP分别位于网络系统的哪一层? 13-2 分析一下当主机是A:192.168.2.4,子网掩码分别为255.255.255.0和255.255.255.125时主机的网络地址与主机地址分别是什么。 13-3 试着用ifconfig配置网络参数,查看网络参数的变化。 13-4 从本机连接到远方主机www.yahoo.com.cn,使用traceroute观察所经历的路由器。
  • 908. 第14章 备份与恢复14.1 备份的重要性 14.2 备份策略和注意事项 14.3 常用备份命令 14.4 文件恢复 14.5 利用cron命令和脚本实现任务的自动化 14.6 小结 习题
  • 909. 计算机系统在运行过程中不可避免地会发生各种故障,备份指定期把用户的数据拷贝到脱机的介质上去,例如,磁带等介质,制作在线数据的一个离线副本。所谓恢复指一旦系统出现故障,能够迅速从离线介质把数据拷贝回硬盘,把因故障引起的损失减少到最小,快速使系统摆脱故障,正常运行的过程称为恢复。本章讨论后备恢复的概念及常用的操作命令。
  • 910. 14.1 备份的重要性 对于许多部门来说,数据比他们的计算机设备更有价值。人们常误认为机器中的数据是万无一失的,而实际上由于这样那样的原因总会引起数据丢失,结果为之付出了惨重的代价。要防止数据丢失就必须执行严格的备份制度,按时做数据的备份和转移工作,即使系统出现故障,也不会造成大的影响,代价仅仅是从备份中恢复丢失的数据。 一般丢失数据有以下几方面的原因:硬件故障、软件缺陷、人为因素或自然灾害。硬盘的损害对数据来说是不可恢复的;另外软件的缺陷也经常会损坏数据;人为因素是不可预料的;而自然灾害一旦发生就是毁灭性的。
  • 911. 14.1.1 选择备份介质 备份介质有很多种,如软盘、便携式硬盘、可写光驱、8mm盒式磁带、4mmDAT磁带等,当然也可以通过网络备份到远程文件服务器的硬盘上。就备份介质的选取而言,需要考虑成本、可靠性、速度、可获得途径、可用性等。可靠性是首要标准。接下来就必须考虑成本。另外需要考虑的就是设备的兼容性。 有些单位的单机备份工作量非常大,可以使用磁带库或自动换带机。但是磁带库一般比较昂贵。
  • 912. 14.1.2 选择备份工具 传统的UNIX备份工具是tar、cpio、dd和dump。还可以使用第三方软件包。 各种备份工具无外乎两种工作模式,要么通过文件系统I/O调用来备份文件或目录,要么通过访问磁盘设备对磁盘块进行直接操作。 “tar”为tape archiver的缩写,和cpio类似,从备份来看二者基本等效,都能将文件存到磁带并取出文件,都能使用几乎所有介质,因为核心设备驱动处理低级设备操作,在用户级程序看来所有设备都差不多。但是cpio有一点不同,它支持设备文件如/dev/hda,这一点与dd类似,dd对于不同UNIX版本间的格式转换和磁盘拷贝非常有用。
  • 913. dump不同,它对文件所在的块设备进行原始的访问来直接备份文件系统,而不通过文件系统调用。如果要备份整个文件系统,它可以减少磁头移动。它的主要缺点是每个文件系统种类需要特定的备份程序,Linux的dump程序只理解ext2文件系统,也直接支持备份级。 Linux上还有一个有用的工具afio,它是cpio的变体,它把文件逐个压缩到备份中,这一点优于tar对整个档案文件的压缩,因为一个极小的错误就可能使被压缩的tar档案文件变得无用,不过这个工具主要应用于Linux系统。
  • 914. 14.2 备份策略和注意事项 14.2.1 备份类型 一个简单的备份方案是一次备份所有数据,或者是备份上次备份后改变的所有数据。前一种备份叫完全备份,后一种叫增量备份。完全备份比增量备份费时费力。但恢复增量备份比全备份可能要花更多的时间。
  • 915. 14.2.2 备份级别 UNIX/Linux利用备份级别来区分不同的备份种类。完全备份为0级备份,其他级别表示的是自上一级别以来被修改过的文件。做0级备份最好保证在单用户模式,尽量保证备份的一致性,以免产生无法恢复的错误。如果必须动态进行,就需要使用好的备份工具,从软件上保证一致性。 下面对表14.1所示两种比较常用的方案进行分析比较,从而对备份策略有更好的理解。
  • 916. 表14.1 两种常用的备份方案方案1方案2星期天0级备份星期天0级备份星期一1级备份星期一1级备份星期二1级备份星期二2级备份星期三1级备份星期三3级备份星期四1级备份星期四4级备份星期五1级备份星期五5级备份星期六1级备份星期六6级备份
  • 917. 方案1的优点是恢复时只需恢复上次完全备份和最后一次增量备份即可,但是如果备份内容很多,则增量备份的数量会很大,需要更多的磁带介质。所以在备份容量不是很大的情况非常适合。方案2的优点是每次备份都比较迅速,且备份内容较少,易于管理,但是恢复时比较麻烦。这种方法可以节省磁带,对于大容量备份较合适。 实际的备份方案有很多种,有些已经利用了一些复杂的数学算法作为备份序列的调度以减少所需的磁带容量,但都是依据备份级别的这些基本规定而制定的。一个好的建议在dump man页中给出,它是一个基于汉诺塔算法修改的调度序列:3,2,5,4,7,6,9,8,9...这使备份和恢复所用的时间保持较少。
  • 918. 14.2.3 备份的注意事项 备份是必要的,而保证正确的备份是绝对必要的。所谓正确的备份就是可以用来恢复系统的备份。首先必须保证物理安全性,备份好的磁带必须从物理上隔离,以免发生火灾这样的毁灭性灾难。其次必须保证备份是可恢复的,要检查备份介质是否损坏,备份恢复工具是否易于获得,只有确保正确的备份才可以送到安全的地方保存。 由于许多时候备份是用cron命令启动的,这时就必须确保需要备份的内容小于磁带的容量,并且要保证磁带不可回绕,否则会覆盖前面的工作,即使是拥有磁带库这样高级的备份工具也一样要仔细检查。
  • 919. 还有备份过程中出现的介质错误,有些磁带坏了,影响了备份,一定要有补救措施,哪怕是最繁忙的时候,也要占用一点主机资源,可以临时将备份内容保存到其他服务器上。 最后要提到的是,做备份时一定要全面了解系统的使用情况。经常改动的文件应该比改动较少的文件备份更频繁一点,而有些目录如/tmp、/var、/mnt等是没有必要备份的,有些目录如/proc则是不应该备份的。
  • 920. 14.3 常用备份命令 本章主要讨论Linux上GNU版本的tar命令。GNU版本能处理一盘磁带或一张磁盘的备份,但不支持备份时采用多卷备份的功能及目录很深的长路径名。 下面的命令把整个Linux文件系统备份到“/archive”文件系统上,必须以root身份执行。 # cd/ # tar -zcvpf/archive/full-backup-`date′+%d-%B-%Y′`.tar.gz --directory/ \ --exclude=proc --exclude=mnt --exclude=archive --exclude=cache 注意: 在备份文件系统时,不要包含/proc虚拟文件系统。也不要包含/mnt和/archive目录下的文件。
  • 921. 下面给出常用的参数含义: z 表示备份的数据将使用gzip进行压缩。 c 表示创建归档文件。 v 显示文件列表。 p 保存权限,文件的访问权限将被“记住”。 f 说明下一个参数就是归档的文件名或设备名。 M 建立/解压/显示多卷档案文件,使用该参数系统会自动提示。 请注意一下带有当前日期的文件名是如何产生的,其方法是在两个反引号之间放入“date”命令。通常的命名习惯是给未压缩的文档加一个“.tar”后缀,经过压缩后的记为“.tar.gz”,或缩写为“.tgz”。
  • 922. “--directory”选项告诉tar先转到规定的目录下(本例中为“/”目录,也可以逐个指定目录),然后进行备份。“--exclude”选项告诉tar不要备份指定的目录或文件。 /archive目录有时就是/mnt目录,如SCSI磁带驱动器/dev/nst0等设备通常都加载到/mnt下,这时/archive和/mnt是同一个目录。 注意: /dev/nst0设备在备份写完后不回卷,因此可以在一个磁带上做多次备份。如果指定设备为“/dev/st0”,磁带在备份写完后会自动回卷。对于在一个磁带上做多次备份的情况,可以用“--label”选项在归档文件里写入一些备份集的信息,以区分每次的备份工作。
  • 923. 使用磁带时,可以用“mt”命令回卷和弹出磁带: # mt -f/dev/nst0 rewind # mt -f/dev/nst0 offline 还有其他参数如“fsf、bsf”等命令,意即“快速前进n个文件、退回n个文件”。详细的信息请参阅在线文档。 授权用户也可以根据自己的实际需要备份指定的文件和目录。
  • 924. 下面给出两个例子: 例1. 仅仅备份某几个文件,键入命令: # tar -cf archive.tar foo bar 此命令在当前目录下把文件foo和bar备份成archive.tar 例2. 把某个目录备份到本硬盘的“/data”文件系统下,键入命令: # tar -zcf /data/backup-`date ′+%d-%B-%Y′`.tar.gz /home/lily/myfirst/ 此外在做好了一个备份之后,你应该使用选项--compare(-d)来检查它是否正确,以保证可靠性:# tar --compare --verbose -f /dev/tape
  • 925. 14.4 文件恢复 当我们需要恢复一个重要文件时,正确的恢复就比定期备份更重要了。恢复的过程会因为备份方案的不同而有所区别。在本节中,我们讨论如何恢复用tar备份过的文件,该命令常见的参数如下: z 表明档案是使用gzip压缩的。 x 表示解压缩档案文件。 v 显示tar命令所做的工作。 p 保持权限;文件保护信息将被记住。 f 后面的参数是档案的文件名或设备。 t 显示档案文件内容
  • 926. 建议用户在文件恢复前观察一下档案文件的内容,可以使用如下命令: # tar tvf档案(这仅适用于未被压缩的文件) 下面的命令将从档案中恢复文件,如前面对整个文件系统建立的备份档案,其恢复的命令格式如下: # cd/ # tar -zxvpf 路径/档案文件名 “-p”选项在解压缩过程中保持了原来的文件属主和权限。如果不需要恢复档案里的所有文件,可以参照以下例子恢复指定的一个或多个文件,命令如下: # cd/ # tar -zxvpf路径/档案文件名 /etc/passwd /etc/shadow
  • 927. 由于给定的文件必须指定完整的路径名,必须先找到文件名在档案中的具体路径,这可以通过“-t”参数配合“grep”命令查找: # cd/ # tar -ztvpf 路径/档案文件名 | grep -i passwd 在这个例子里,档案中的所有文件名被列出。输出结果被重定向到grep命令,grep的“i” 选项忽略了大小写,显示出路径或文件名中含passwd的所有文件。一旦找到了要恢复的文件,就可以指定文件名并使用上面的tar命令。
  • 928. 下面是使用tar命令的一些注意事项: 当创建档案文件时,tar会去掉文件路径开头的“/”斜线字符。这意味着文件恢复的位置可能和它备份时的位置不一样。因此,解决问题的办法就是在根目录下做所有的备份和恢复。否则必须通过比较、移动或更新把文件恢复到原来的位置。如果系统里有文件被“chattr”命令设了不可变位,这些文件在恢复的时候将不会保持该位。必须在备份结束后再使用命令“chattr”重新设置不可变位。 tar永远是顺序读一个备份卷,因此大的卷会很慢。使用磁带机或其他顺序介质时不可能使用随机存取数据库技术。
  • 929. tar不处理删除文件属性。如果你需要从一个全备份和一个增量备份恢复一个文件系统,并且2个备份之间你删除了一个文件,当你恢复完后,这个文件又存在了。如果这个文件包含应该删除的敏感数据,应该及时删除。 注意: 压缩备份并不是完全可靠。压缩过程中,如果某一个比特压缩出错,那么其余所有的压缩数据都将毫无用处。所以对于十分重要的数据最好不要采用压缩备份。
  • 930. 14.5 利用cron命令和脚本实现任务的自动化 cron命令用来执行周期性的任务,由crond守护进程处理。系统启动后cron就保持运行,它定时读取配置文件,配置文件格式如下: minute hour day month weekday username command 其取值范围如表14.2所示:
  • 931. 表14.2 各时间参数的意义参数说明取值范围minute小时中的分钟数0~59hour每天的小时0~23day每月的第几天1~31month每年的第几个月1~12weeday每周第几天1~7
  • 932. 其中各时间参数可以用通配符“*”代替,表示任一分钟、小时、天等等。username是passwd文件中有效的用户,不同的用户可以有自己的配置文件,可以通过crontab命令编辑、修改、删除用户自己的定时任务,配置文件通常放置在/etc目录下,命名为crontab,cron命令每隔一段时间扫描一次配置文件,并为每个有定时任务的用户在/var/spool/cron目录下建立用户独立的定时文件,文件名即为用户名。如为用户lily的/home/lily/first编辑定时任务: # crontab -u lily /home/lily/first –e 这时/var/spool/cron目录下就可找到lily文件。
  • 933. 14.6 小结 备份工作对于系统管理员是非常重要的,但是对普通读者来说,很少有机会接触磁带机等设备,在现有的条件下熟练掌握tar等基本命令的使用,我们可以利用本地硬盘创建档案文件,达到学习与掌握的目的。这些归档命令在其他场合也是非常有用的,比如说要通过命令行方式从某台服务器下载某个目录下的所有文件及目录,就可以打包后再下载一个tar档案文件即可。另外,掌握cron命令不仅可以灵活地安排备份任务,还可以灵活方便地执行任何shell命令,因为配置文件中的命令行是由sh程序执行的。
  • 934. 习题 14-1 试着利用cron命令安排某个用户的备份任务。
  • 935. 第15章 XWindow及Genie应用程序15.1 Xwindow 15.2 XWindow的配置 15.3 如何启动XWindow系统 15.4 常用的窗口管理程序 15.5 XLinux的系统配置应用程序Genie 15.6 小结 习题
  • 936. 本章介绍应用程序XWindow和Genie。XWindow是一个基于窗口的图形用户界面。20世纪80年代由MIT发布,以后成为UNIX/Linux系统图形工作站事实上的工业标准,可以免费获得,支持多种硬件平台。Genie设置向导是网虎国际开发团队设计开发的智能型设置工具,针对繁琐的Linux设置程序与指令,网虎特地设计此对话式的图形设置界面,让用户对设置Linux的印象不再是一堆繁长难记的指令。利用Genie智能型设置向导,你可以轻轻松松地设置你想要的Linux系统。
  • 937. 15.1 XWindow的工作原理 XWindow系统是一个网络窗口系统,它跟别的网络系统一样,提供基本的通信协议和功能。XWindow系统通过位图化的显示构造计算机的图形界面。XWindow系统有时候也简称X系统或者X11系统。在以后的叙述中,为了方便起见,我们将简称XWindow系统为X。值得注意的是,不要将XWindow系统称为XWindows,这是一个不恰当的称呼。
  • 938. X最初在80年代由MIT(麻省理工学院)开发成功。X的第一个商业版本——X版本10(即X10)在80年代中期推出,在这以后,X的后一个版本——X版本11R1在1987年推出。最初的MIT开发团体现在已经解散,现在X属于The Open Group公司。不过X11通用的客户机/服务器操作模式一直没有改变,X11网络通信的协议就叫X协议。
  • 939. 许多Linux发布系统(包括RedHat,XLinux等)都使用XWindow系统。这个X系统由XFree86 Project组织完成,它是免费的,而且支持多个操作系统平台。包含在RedHat Linux6.0中的X11版本是XFree86 3.3.3.1,基于X11R 6.3。XLinux1.5中包含的X系统版本稍新一点,是XFree86 3.3.6。X的最新版本是X11R6.4。XFree86的下一个有较大变动的版本是XFree86 4.0。据XFree86组织声称,XFree86 4.0将基于X11R6.4。也许读者注意到了,这里提到了X版本和XFree86版本,事实上这两者是不一样的,X是一个标准,XFree86是X的一个免费实现。
  • 940. XFree86的版本号可以在X会话中验证。在控制台上,是按照以下方法使用的带-showconfig参数的X命令: # X -showconfig XFree86 Version 3.3.3.1/XWindow System (protocol Version 11,revision 0,vendor release 6300) Release Date: January 4 1999 If the server is older than 6-12 months,or if your card is newer than the above date,look for a newer version before reporting problems.(see http://www.XFree86.Org/FAQ)
  • 941. Operating System: LinuX2.0.32 i686 [ELF] Configured drivers: VMware: server for VMware virtual graphics adaptors(Patchlevel 0) # X -showconfig XFree86 Version 3.3.6/XWindow System (protocol Version 11,revision 0,vendor release 6300) Release Date: January 8 2000
  • 942. If the server is older than 6-12 months,or if your card is newer than the above date,look for a newer version before reporting problems.(see http://www.XFree86.Org/FAQ) Operating System: LinuX2.2.14-1mdkmosiXi686 [ELF] Configured drivers: SVGA: server for SVGA graphics adaptors(Patchlevel 0): NV1,STG2000,RIVA 128,RIVA TNT,RIVA TNT2,RIVA ULTRA TNT2,
  • 943. 从上面的输出我们可以看到两个不同的XFree86版本,其中一个是3.3.3.1,另一个是3.3.6。同时,从上面的输出还可以知道X服务器的发布日期、操作系统、支持的设备驱动等信息。 X系统支持网络图形。在X协议中,X应用程序称为客户。X客户并不直接控制显示器或者操作图形,而是与X服务器通信,通过X服务器控制显示器,也就是说,实际中的绘图和显示工作都是由X服务器来完成的。由X协议的体系结构决定,X应用程序(即X客户)可以在网络上的任何一个地方运行,而都显示在用户面前的一台计算机上——这台计算机运行的就是X服务器,在这种情况下,X客户无论在什么地方,对于显示的效果是没有影响的,
  • 944. 或者说,对于显示是透明的。也就是说,可以在单台计算机上运行X服务器,从远程计算机启动多个客户——并通过本地服务器在本地显示。每个X客户与X服务器的通信叫做一个X会话。可以说X是一个网络窗口系统。实际上,X可以在各种类型的网络上运行,包括串行拨号线路。总之,X系统是一个客户机/服务器的体系结构。X服务器负责具体的硬件相关的绘图工作,X客户通过网络跟X服务器通信。X客户不直接操作显示硬件,而是通过X服务器来完成绘图工作。
  • 945. 15.2 XWindow的配置 15.2.1 建立XFree86系统 XFree86系统是Linux图形界面的基础。尽管不使用X也可以使用Linux,但是许多有用的应用程序需要X系统的支持。X系统也令Linux系统更加丰富多彩。 如果在第一次安装Linux系统(比如XLinux)时选择了安装和配置X11,则在硬盘上的/usr/X11R6目录中可以找到X系统的大部分文件。如果原来系统中安装了旧版本的X系统,你也可以选择使用rpm命令升级X系统。首先插入XLinuxCD-ROM,然后以root身份加载,如下所示: # mount/dev/cdrom/mnt/cdrom
  • 946. Linux系统中,/dev/cdrom通常是一个符号连接,指向用户实际的CDROM设备。 在加载了CDROM以后,就可以从/mnt/cdrom/package目录下使用rpm命令来升级X系统了。在一个终端窗口或者控制台可使用如下命令: # rpm-Uvh XFree86*.rpm 这个命令将升级XFree86软件,如果原来没有安装X系统,则该命令将安装XFree86软件。有关rpm命令的具体参数,可以通过查看rpm的手册页获得,本书在第10章Linux系统安装部分也有详细的说明。 软件安装完成后,可以在硬盘的/usr/X11R6目录下找到许多目录,包括:
  • 947. /usr/X11R6/bin大多数X应用程序目录 /usr/X11R6/include编程头文件和位图及像素图目录 /usr/X11R6/libX应用程序和X程序开发需要的X11链接库 /usr/X11R6/manX手册页 X11的目录可能要占据40~400 MB的硬盘空间,具体大小取决于安装的软件。如果安装更多其他的XWindow管理器、编程开发库或其他X应用软件,则可能需要更多空间。
  • 948. 对于典型安装的XFree86系统来说,其主要组件包括多种X服务器(约10个)、各种配置文件、各种应用程序、编程用的头文件和开发链接库、字体、资源(客户配置)文件和手册页等。关于XFree86系统配置更详细的信息,可以参考硬盘上/usr/X11R6/lib/X11/doc目录中的README.config文件。我们在以后也会提及到。
  • 949. 15.2.2 配置XFree86系统 安装XFree86系统最困难、花费时间最多并且容易受挫折的步骤之一是配置XF86Config文件。该文件最初在安装时生成。例如在XLinux1.5安装时选择安装X11,安装成功则会出现一个窗口图形界面。在升级计算机显存或者安装新的显示卡的时候,可以重新配置XF86Config。 一般来说,安装后生成的XF86Config是可用的,以后可以在原先的XF86Config文件上修改。另一方面,如果从头开始配置XF86Config文件,则在安装X以后,第一件要做的工作是阅读尽可能多的文档。有经验的用户可能从阅读最新的XF86Config开发文档和检查XFree86文档中关于特定硬件的文档中得到各种有用的信息。
  • 950. 在配置XFree86系统过程中,几乎所有需要的信息都可以在/X11R6/lib/X11/doc目录中找到。你可以在这个目录下发现有关协议、开发库、应用程序和其他服务的详细信息。另一个重要的文件是/usr/doc/HOWTO目录下的XFree86-HOWTO文件。这个文件包含关于配置X系统的很有用的信息。 下面详细描述配置XFree86系统的大致过程。 在配置XFree86系统之前,如果对X很陌生,用户需要先阅读X和XFree86的手册页获得对X的大致了解。此外,用户还需要阅读QuickStart.doc文件。此时,用户应该已经有了对X的初步了解。
  • 951. 然后,用户需要了解有关自己的计算机及其显卡和监视器的一些硬件细节。主要有: · 显卡的类型、制造商、名称或型号 · 显存大小 · 显卡芯片组使用的时钟芯片类型 · 鼠标类型(例如PS/2鼠标或者串口鼠标) · 显示器的类型、制造商、名称或型号 · 显示器垂直和水平刷新频率(如55~100Hz垂直,30~60Hz水平) · 键盘的类型
  • 952. 了解这些信息之后,接下来需要选择配置XFree86系统的方法和工具并生成正确的XF86Config文件。XFree86的配置工具主要有以下几种:图形化的X11设置工具Xconfigurator程序、XFree86的XF86Setup程序、XFree86的文本模式工具XF86Config程序。此外,用户也可以用文本编辑器手动构造自己的XF86Config文件。我们在后面会提到用XLinux带的智能配置工具genie程序也可以完成这项工作。
  • 953. Xconfigurator和XF86Config程序从控制台或者终端的命令行运行。Xconfigurator的优点是提供图形化的界面;而XF86Config在文本模式的窗口中询问一系列的问题。如果用户比较幸运,所安装的计算机的硬件将很容易在程序中找到合适的配置。但是如果这些设置无效、输入的信息不正确或者选择的XFree86服务器不完全支持该视频芯片组,则可能会产生各种问题。 通常来说,稍旧的显卡比新显卡要容易配置一些,原因是程序员有机会对显卡的芯片组进行处理。笔记本电脑显卡的配置可能更加艰难。如果遇到问题,较好的做法是访问互联网上的Linux讨论组,也许能够获得某些人的帮忙。
  • 954. 如果不能正确的设置显卡或者显卡的型号不在XFree86系统的支持之列,还有一个方法就是从宣布支持该硬件的软件商处购买商业版本的X,比如说Accelerate X。或者从XFree86源代码重新编写一个服务器(那就从现在开始研读源代码吧)。 15.2.3 XF86Config文件 毫无疑问,XFree86最重要的配置文件是XF86Config文件。该文件用于正确地配置字体、键盘、鼠标、显卡芯片组、显示器等X服务器的配置信息。当启动一个X会话时,X服务器要搜索这个文件。XF86Config一般放置在/etc/X11目录中,在别的系统中也可能在/usr/X11R6/lib/X11目录下。 XF86Config是一个单独的文本文件,由几部分组成:
  • 955. · 文件颜色、字体或特定的软件模块的位置。 · 模块要装载的特定的模块。 · 服务器标志开/关标志允许或者禁止特定的操作,如内核转储、键盘服务器关机、视频模式切换和鼠标以及键盘配置。 · 键盘键盘设置。 · 指针设备指针设备(pointers)以及键的处理方式。 · 输入输入设备,如图形板或者光笔。 · 显示器指定监视器的细节和设置,如名称、水平同步与垂直同步范围以及模式行(每种分辨率一个值,如640×480、800×600、1024×768)。 · 设备关于视频芯片组的详细信息,如RAM 或者时钟芯片。 ·
  • 956. 屏幕颜色深度(如8、16、24或者32位)、屏幕尺寸(如640×480、800×600或1024×768)、虚拟屏幕尺寸等等。 值得注意的是,不要使用与自己的显卡和显示器不匹配的XF86Config。错误的设置(比如错误的刷新频率)可能损坏显示器。在你手动修改XF86Config文件以前,确保你已经阅读了README.Config,并且明白你将要做些什么事情。 下面简要解释一下XF86Config文件的各个部分: 1. Files 部分
  • 957. Section ″Files″ # RGB数据库路径。 RgbPath ″/usr/X11R6/lib/X11/rgb″ #字体目录路径,可以是文件目录路径或者X字体服务器路径,比如说下面的“UNIX/:-1”。FontPath ″UNIX/:-1″ EndSection 关于字体目录的路径,以前的版本只能是文件目录的路径。现在增加了xfs字体服务器的支持。xfs字体服务器的路径形式一般是“主机/:端口”,-1表示默认端口。关于xfs字体服务器设计和操作的详细信息,可在/usr/doc/XFree86-doc*/xfs目录的design.ps.gz文件中找到。
  • 958. xfs的配置文件在/etc/X11/fs目录下,文件名为config。该文件的catalogue项目下包括一个字体目录列表,如下所示: catalogue =/usr/X11R6/lib/X11/fonts/misc:unscaled, /usr/X11R6/lib/X11/fonts/75dpi:unscaled, ... /usr/X11R6/lib/X11/fonts/Speedo, /usr/share/fonts/default/Type1
  • 959. 2. ServerFlags部分 Section ″ServerFlags″ #是否Core Dump(用来调试)。 # NoTrapSignals #是否可以用Ctrl-Alt-BackSpace来结束一个X会话。 # DontZap #是否可以用Ctrl-Alt-KP-+/KP--(这个是小键盘上的+/-)切换显示模式。 # DontZoom EndSectionServer Flags用于配置XFree86服务器允许的特殊操作。通过删除特殊标记前面的#符号
  • 960. 可以启用特殊操作。一般的应用会保留DontZap特性,因为它提供一种快速退出X会话的方法。如果使用的X只支持一种分辨率模式,如800×600像素,则可以禁止DontZoom特性。 3. Keyboard部分 Keyboard部分通知X服务器希望的键盘类型以及使用的设置,如语言类型、键盘字符布局以及制造商。 4. Pointer部分 Pointer部分通知X服务器使用的指点设备(或者说鼠标)的类型和键的设置。注意串口鼠标类型为Auto,总线鼠标为BusMouse。而Device项目中/dev/mouse实际上是实际设备(如PS/2鼠标为/dev/psauX,串口鼠标为/dev/ttys0)的符号链接。
  • 961. 两键鼠标用户可能要启用三键模拟(同时按下左右按键模拟按下中键),点击中键通常都用于粘贴文本或者图形。关于配置鼠标更详细的信息,可以参考/usr/X11R6/X11/doc目录下的README.mouse文件。 5. Monitor部分 XF86Config文件的前几部分都容易理解,而更重要的配置部分是Monitor部分、Graphics Device部分以及Screen部分。 Monitor部分包含关于监视器的详细信息和设置,如监视器名称、水平和垂直同步范围以及关键的模式行(对应每一种分辨率有一个值——如640×480、800×600、1024×768),了解模式行是调整X11
  • 962. 显示的关键。在调试XF86Config文件中的模式行之前要了解尽可能多的信息,请参阅/usr/X11R6/lib/X11/doc目录下的VideoModes.doc和README.Config文件。另一个好的指南是/usr/doc/HOWTO目录下的XFree86-Video-Timings-HOWTO。 模式行的基本部分有10个不同的值(从左到右): · 屏幕分辨率标志,如800×600。 · 显示频率(MHz)。 · 屏幕上每行显示的点数。 · 起始水平回扫(SHR)值(在视频同步脉冲开始之前的脉冲数)。 ·
  • 963. 结束水平回扫(EHR)值(同步脉冲结束)。 · 屏幕上可见和不可见的总点数。 · 垂直显示终止(VDE)值(屏幕上点的可见线个数)。 · 起始垂直回扫(SVR)值(在同步脉冲开始之前的行数)。 · 结束垂直回扫(EVR)值(同步脉冲结束时的行数)。 · 垂直总数(VT)(在屏幕上可见和不可见的总行数)。 关于这一部分修改一定要慎重,除非十分清楚你在做什么。
  • 964. 6. Graphics Device部分 Graphics Device部分包含有关显卡芯片组的细节,如显存和时钟芯片。注意即使用户告诉Xconfigurator有2MB显存,Xconfigurator也会使用“#”符号注释该选择。要正确地配置X,需要删除XF86Config文件中该部分VideoRam设置前面的“#”符号。 关于设备标识符和选项的列表请参阅/usr/X11R6/lib/X11/doc目录下对应芯片组的README文件。 7. Screen部分 Screen部分配置X服务器使用的颜色深度(如8、16、24或者32位)、屏幕尺寸(如640×480、800×600或
  • 965. 1024×768)和虚拟屏幕尺寸(这个是可选的)。其中颜色深度在用户使用startx命令时,可以用-bpp选项覆盖。startx命令是启动X会话的简便途径。如果显卡和监视器支持,可以按照如下方式启动16位颜色深度的X会话:# startx-bpp16Screen部分还包括用户选择的X服务器(包括XF86-SVGA或者其他颜色服务器、4位或者16位颜色XF86-VGA16或黑白服务器XF86-Mono)支持的分辨率和虚拟屏幕尺寸的说明。在一个X会话中,用户可以通过按住Ctrl+Alt键再按下小键盘的“+”或者“-”键来切换分辨率。
  • 966. 15.3 如何启动XWindow系统 启动X会话最简单的方法可能是使用startx命令,实际上,startx是一个shell脚本,它传递命令行选项给X服务器以创建一个X会话。startx命令通常用于传递启动的颜色深度信息到X服务器,它还可以查找客户程序命令或者选项以运行该会话(通常是用户目录中的.xinitrc文件)。.xinitrc文件记录窗口管理器的使用或者其他X客户程序启动的细节。用户可以在/etc/X11/Xinit目录中找到一个模板文件xinitrc。把该文件复制到用户主目录中并改名为.xinitrc,然后就可以参照它的格式进行需要的修改了。
  • 967. 除非在系统的XF86Config文件中用DefaultColordepth选项设置了特定的颜色深度,否则startx使用8位颜色深度(或256色)启动X会话。但是,可以通过使用--和-bpp选项传送颜色深度信息选项到服务器:该命令行将使用16位颜色深度启动一个X会话(如果计算机的显卡和监视器支持)。使用-bpp选项传送的颜色值通常还包括24和32以设置几百万种颜色。还可以使用startx在一台计算机上启动多个X11会话,可能使用不同的窗口管理器,然后使用虚拟控制台在各个会话之间转换。XLinux支持最多6个登录屏幕和控制台,通过按下Alt+FX进行访问。这里FX从F1到F6。例如,如果不使用显示管理器登录到Linux,则处于第一个
  • 968. 虚拟控制台;在登录以后,按下Alt+F2,则在第二个控制台显示登录提示;要返回第一个登录窗口,按下Alt+F1;当登录到Linux并使用startx启动X11会话之后,X使用第7个虚拟屏幕;因为用户从第一个虚拟屏幕启动X,该屏幕将不可使用,但是,可以获得另一个虚拟控制台,如第二个(通过按下Ctrl+Alt+F2),则用户将看到Linux登录提示;要回到X会话,按下Alt+F7。使用该方案,可以在X会话和不同的文本控制台之间来回跳转。 xdm(即X显示管理器)是一个X客户程序,也是Linux包括的三种显示管理器之一。使用该程序在引导Linux时可以提供小级别的安全性。可以使用xdm登录到Linux并直接进行X会话,可以在本地,
  • 969. 也可以使用远程的计算机。但是如果选择不使用显示管理器或者直接引导到X,可以作为root操作员在命令行使用带-nodaemon选项的xdm命令。 该命令清屏并显示xdm登录屏。然后可以登录到X或者使用Ctrl+Alt+F1退回到控制台并使用Ctrl+C杀死守护程序。 解决使用XFree86的X11安装或者其他问题的最好资源之一是XFree86 FAQ,它在http://www.XFree86.org可以找到。这个FAQ包含7个部分并解决以下问题: · 配置问题 · 键盘和鼠标问题
  • 970. · 显示问题 · 使用字体的问题 · 使用到X(X服务器)的符号链接的配置问题 · 芯片组支持补丁 · 其他已知问题 注意如果在X手册页、FAQ或者其他文档中找不到答案,则在comp.so.linux.XUsenet新闻组稍加浏览。可以邮寄问题、简单明了地指明你的Linux软件状态以及版本还有安装的XFree86版本。注意如果无法访问comp.so.linux.x或者如果不喜欢使用Usenet新闻阅读器查找Linux和X11的问题解答,可以将Web浏览器指向http://www.dejanews.com。
  • 971. 15.4 常用的窗口管理程序 本章涵盖XWindow系统的各种窗口管理器。X11提供基本的网络协议和绘制原语以构造用户可以使用的各种图形界面平台或者窗口管理器。这些客户程序(如twm)来自XFree86,同时,其他的程序(如Carsten Haitzler的启用GNOME的EWM)使用Red Hat软件公司支持的X客户程序以提供完全的桌面环境。还包括KDE,它是一个类似的功能更成熟的桌面软件产品,是与商业的通用桌面环境(CDE)竞争的产品。
  • 972. 15.4.1 什么是窗口管理器 使用Linux的XFree86软件产品意味着选择自由——选择操作系统和选择计算机桌面或者X中的窗口外观的自由。尽管窗口管理器只是一个X11客户程序,读者将发现如果希望运行不同的程序、在屏幕上拖动窗口、使用图标、创建虚拟桌面、更改窗口尺寸或者定制X会话的工作,使用窗口管理器实际上非常必要。当然,可以运行没有窗口管理器的X,但是会减少许多功能。
  • 973. 15.4.2 GNOME GNOME即GNU网络对象模块环境,该软件由来自Red Hat软件公司和世界各地的程序员支持和开发。GNOME备受关注,因为该软件基于GNU GPL发布,不像底层的图形软件库,如KDE的Qt。除了许可限制协议这一原因外,GNOME成为Linux图形化的X桌面特性的重要部分,还有以下几点原因: · 该软件完全开放源码,任何人可以销售;基于该软件的商业软件无需购买软件许可。 · 允许赠送、改变和修改,无需通过集中资源控制,对于更改和发布更改没有许可的限制。 · 软件支持多操作系统和外部编程语言。
  • 974. · 该软件可以和任何GNOME可以识别的X11窗口管理器一起工作,如Enlightenment。 GNOME是一组支持X11桌面环境的软件库和X11客户程序。GNOME可以和任何GNOME可以识别的窗口管理器,或者支持其面板组件和客户程序功能(如拖放动作)的窗口管理器一起工作。GNOME在窗口管理器启动前初始化和运行。和KDE一样,GNOME提供良好的用户环境,包括应用程序框架、文件管理器、面板、一组外观一致的应用程序以及会话管理,因此可在X11会话之间保存和恢复工作桌面。
  • 975. 15.5 XLinux的系统配置应用程序Genie 15.5.1 Genie简介 Linux的配置基本上都是通过编辑一些文本文件来完成。但是对于一般的用户,特别是刚接触Linux的用户,这种方式可能有点不便。于是各种版本的Linux发布都会提供一些可视化的配置程序。以XLinux为例,XLinux的系统配置可以通过一个叫Genie的可视化程序来完成。 Genie的配置方式主要是对话式的配置模式。在这种方式下,用户不用记忆Linux那一堆纷繁复杂的指令,很轻松就可以完成各种设置方式,所以特别适合入门的用户,对于高级用户,有时候也是合适
  • 976. 的,毕竟Linux的各种配置文件和指令太多了,没必要把各种东西都弄得很熟悉。 Genie可以完成硬件(如键盘、鼠标、打印机等外设)设置、时区设置、系统服务、网络服务、XWindows配置等等。 要激活Genie设置向导,只需要在shell里键入“genie”,或者按Alt+F12切换到Genie控制台来完成。 Genie的预定设置项目包括以下几方面: (1) 硬件设置 (2) 系统设置 (3) 网络设置
  • 977. 使用Genie的时候,需要注意几点: (1) 建议在console模式下执行Genie设置向导; (2) 以root身份执行Genie设置向导; (3) Genie设有登录密码保护,Genie的登录密码与root密码相同。如果用户连续输入3次错误的密码,则Genie画面将锁住1分钟。 15.5.2 Genie硬件设置 启动Genie设置向导并选择Genie硬件设置,即可进入硬件设置窗口,如图15.1所示,Genie硬件设置包括鼠标设置、键盘设置、串口设置和打印机设置等。
  • 978. 图15.1 硬件设置
  • 979. 1. 鼠标设置 鼠标设置程序帮助设置机器上的鼠标。 选择Mouse Setup后按Enter键,进入设置区。鼠标设置程序会先检测系统的鼠标设备,在出现检测画面选择确定后按Enter键,就可以进行鼠标型号的设置。从列表中选择你的鼠标型号,以Logitech ps/2 mouse为例,可以选择Logitech MouseMan/FirstMouse(ps/2)。选定鼠标型号后,按Enter键接着进行。当鼠标左右键同时按下时为是否模拟鼠标第三键的设置。如果要选择鼠标左右键同时按下时模拟鼠标第三键,则选择Emulate 3 Buttons。
  • 980. 设置完成后,鼠标设置程序将重新应用配置文件使得修改生效。然后会回到Genie主画面。 2. 键盘设置 键盘设置工具用来定义键盘的映射类型。 选择Keymap Setup,按Enter键进入设置区。然后选择您所要的键盘定义,默认值是us.kmap.gz,一般来说这个默认值是合适的。 设置完成后就会生效。 3. 串口设置 串口设置程序主要用来检测目前串口的设置,包括I/O端口的设置、IRQ的设置和串口传输速率的设置。
  • 981. 选择View可以显示出当前状态。 选择Setup可以设置串口。 一般来说,串口的默认设置就可以正常工作。所以这个设置工具用得并不多,特别对于初级用户。 4. 打印机设置 打印机设置向导可以设置本机打印机和远程打印机,包括UNIX打印机,Windows网络邻居共享的打印机,以及Novell Netware上的打印机。 我们以设置本机上的HP 4L打印机为例,说明打印机设置的使用方法: 例: 增加打印机 选择Printer Setup|Add,画面会有若干个选项:
  • 982. LOCAL本机打印机 REMOTE远程UNIX打印机 SMB 远程Windows网络邻居打印机 NCP 远端Netware打印机 我们选择LOCAL,然后进入“Config local printer”的画面,这里也有几个选项: Name 打印机名称 Spool 打印机暂存文件目录(用默认值就行) Limit 打印文件大小限制(通常设为0,表示无限制) Device 打印机设备名称 Filter 打印过滤器(指定printer所使用的Filter) Done完成
  • 983. 我们选择Name,按Enter键进行设置,输入HP4L;选择Limit,输入0;选择Device,按Enter进入设置区,选择打印机端口,在例子中是lp0,lp0即DOS下的lpt1,这个选项不同的环境可能是不一样的;选择Filter,可以设置纸张大小及打印精细度;选择Done完成设置。 15.5.3 Genie网络设置 网络设置窗口见图15.2,下面详述设置内容。
  • 984. 图15.2 网络设置
  • 985. Genie的网络设置包含以下功能:系统网络设置和上网设置。 1. 系统网络设置 系统网络设置用来设置、管理主机的网络环境如(主机名称、IP地址)、网卡、路由器以及包过滤策略(可以用ipchains设置)。 (1) 主机信息 选择System Network Setup|host按Enter进入设置区。主机信息设置包括:网域名称、主机名称、域名服务器地址及域名查询顺序。选定选项按Enter按照系统提示,设置相应的项,例如网域名称:xlinux.com.cn,主机名称:genie,域名服务器地址:192.168.0.1。
  • 986. (2) 网卡 选择System Network Setup后,按Enter键进入设置区选定interface选项。网卡信息包含:网卡名称、地址设置及开机是否启动。 新增网卡: System Network Setup|interface|addif按Enter进入,输入设备名称后进入设置画面。选择ipaddr输入IP地址。选择netmask输入网络掩码,设置精灵会自动计算network ip及broadcast ip。选择onboot选择yes可以使开机时自动启动网卡。离开时精灵会询问是否立即启动设置,只要回答yes之后即可立即启动无须重开机。
  • 987. 修改网卡设置: System Network Setup|interface|modifyif按Enter进入。选择欲修改的网络设备后如同“新增网卡”步骤。 删除网卡设置: System Network Setup|interface|removeif按Enter进入选择欲删除网卡设置。再确认是否真要删除,若回答yes,则该网络设置将会被删除。 (3) 路由表 选择System Network Setup后,按Enter键进入设置区选定router选项。选择gateway输入网关IP。
  • 988. (4) ipchains 选择System Network Setup后,按Enter键进入设置区选定ipchains选项。这是用在有两个以上的网络卡,透过ipchains来做IP-Masquerade(NAT)及anti-spoofing。假设eth1为192.168.0.0/255.255.255.0,eth0为public ip,则选择publicdevice,输入eth0,选择privatenet,输入192.168.0.0,选择netmask,输入255.255.255.0。
  • 989. 2. 上网设置 上网设置精灵可让你设置调制解调器Modem,通过ISP方便你拨接上Internet,你可设置多组设置文件分别连接上不同的ISP公司,除了可以新增各个不同的设置文件,也可删除不合时宜的设置,或是执行拨接程序连上ISP,以及中断连线。这里将以263.net为例示范如何使用本设置精灵。 (1) 使用设置精灵 选择Modem Setup后,按Enter键进入设置区:选定setup|Next。输入连线设置文件名称如263.net(请小心不可输入空格键),然后按Enter键进入设置区,请选定PAP。PAP是Windows 95所使用的验证方式,现在各ISP均支持此种认证方式。下面在password
  • 990. 项中输入ISP所给定的密码。在UserID中输入你在ISP所登记的用户名称。(注意请勿包含任何空格键),设置Modem的连接口为/dev/ttyS1(COM2),清除defaultroute区和IP输入,使用ISP动态给定的IP和路由。设置你的Modem上网速率为115200。在Number to dial中输入电话号码。263.net的电话是2631,最后将光标移至ATDT并按下空白键将ATDT mark起来,选Finish保存设置。 (2) 如何拨号上网 选择Modem Setup后,按Enter键进入设置区,选定dialup。选择你想拨接的拨号设置文件,此时选择263.net按Enter键后完成拨号动作。此时你将会听到modem的拨号声,请稍待片刻待modem与ISP
  • 991. 完成连线动作后也就完成上网的整个动作。如果还是有错,请回到设置选项调整设置,或是询问ISP及modem制造商询问一些网络设置细节。 (3) 如何切断连线 选择Modem Setup后,按Enter键进入设置区,选定hangup即可。 15.5.4 Genie系统设置 系统设置见图15.3。
  • 992. 图15.3 系统设置
  • 993. Genie的系统设置包含了以下的设置功能: · 系统备份 · 核心模组载入程序 · 动态载入库设置 · PAM 设置 · 系统时间与时区设置 · User/Group/Quota设置 · 使用者默认登入环境设置 · 例行性事务设置 · 环境变量设置工具 · 系统服务启用工具
  • 994. 系统备份设置可以轻易地设置备份设备、备份来源、备份周期等。 核心模组载入程序用于动态地载入模块,如网卡驱动程序模块。 动态载入物件设置精灵可让您设置动态载入库的目录。 PAM设置可以用来限制使用者连线的来源,上线的时间,控制台使用者的特权以及root登入的限制。 Date/Time设置工具帮你轻易设置系统日期时间,以及你所在的时区。 User/Group/Quota设置工具帮你轻易新增、修改、删除、设置用户账号、组、以及设置Quota(用户可使用的硬盘空间)等。
  • 995. 用户默认登入环境设置可以新增、编修、删除用户默认的登入环境。 例行性事务设置精灵让你依每分、每时、每日、每周或每月来安排周期性的工作。 环境变量设置工具整合了多项系统变量的设置功能,提供下列内容修改: · 改变系统提示符号 · 设置文件名色彩 · 修改账号建立时的默认配置文件 系统服务启用工具是一个操作简易的协助日常的管理工具。它可以帮助你管理系统中各服务程序在开机时启用与否。
  • 996. 15.5.5 Genie动态设置项目 XLinux的Genie动态设置项目是使用RPM包装好的文件,可以很容易地加入其他server(服务器)的设置程序,“Genie的动态设置项目”可帮助设置其他特别的server功能,甚至XWindow的设置也可以交给它。只要在安装XLinux时安装了以下的套件,便可以选择相对应的Genie设置项目,动态地加入系统,以方便设置。 可以在XLinux的光盘中找到其所属的rpm文件(位于XLinux光盘的/package目录下),用rpm的方式将它安装到系统中,以下为Genie的动态设置项目及它们在XLinux光盘中所属的RPM文件名称:
  • 997. · XWindow Setup · Sendmail设置 · fetchmail设置 · 网络文件系统(NFS)设置 · 网络文件系统服务器(NFSD)设置 · Samba设置 · Apache设置 · Inn设置 · 网络对时协议(NTP)设置 · 网络对时协议服务器(NTPD)设置 安装步骤如下:
  • 998. ① 先将XLinux光盘放入CD-ROM中,再通过以下指令将光盘驱动器挂接到文件系统中: # mount/mnt/cdrom ② 切换到光盘中的package目录下 # cd/mnt/cdrom/package ③ 用rpm指令安装Genie的动态设置项目,例如要安装fetchmail的Genie设置项目可输入以下指令:rpm-ivh [-force] Genie动态设置项目rpm文件名称注: “-force”选项表示如果系统中已有同名软件包就替换它
  • 999. 例如你要安装的Genie动态设置项目是fetchmail:#rpm-ivh-force-genie-fetchmail-19991125 1XL .noarch.rpm genie-fetchmail ########################### ④ 把CD-ROM的文件格式卸下(umount): # umount/mnt/cdrom ⑤ 回到Genie的主设置画面,所安装的Genie动态设置项目已经被加入设置画面。按照Genie的默认项目使用即可。 现在,让我们介绍Genie的动态设置项。
  • 1000. (1) XWindow设置精灵 XWindow精灵帮你轻松地设置启动X时所需的硬件相关资料与参数。 设置时只需进行如下步骤即可: · 选定显示卡品牌,程序会自动检测 · 选定显示器厂牌型号 · 选定显示卡内存容量 · 选定ClockChip,一般用默认即可 · 选定显示器色彩 · 选定分辨率
  • 1001. (2) Sendmail设置 Sendmail设置工具可以通过修改宏文件(sendmail.mc)产生可靠的正确设置文件。 在Sendmail设置中可以设置如下内容: · 设置转信收件人(Aliases) · 设置主机别名 · 阻挡垃圾信件 · 更新设置文件,重新启动邮件服务器 邮件服务器的配置是一件比较复杂的工作,如果不了解邮件系统的工作原理,你可能觉得那些宏命令不可理解。建议认真阅读随软件包发布的文档,并向有经验的人请教。
  • 1002. (3) Fetchmail设置 Fetchmail提供远端取信以供离线阅读,并提供下列功能: · 自动侦测远端使用的协议 · 利用smtp做信件分配的工作 · 多账号收信 · 后台执行 · 信件过滤 · 信件分配 · 多主机转信 · 支持多种协议如imap,pop3,etrn等 · 支持IPV6
  • 1003. · 支持IPSec (4) 网络文件系统服务器(NFS)设置 NFS允许您使用远端主机中的文件,就像使用本地机器上的文件一样。此功能是结合客户端的核心函数与服务端的NFS服务器来完成的,而这些经过不同的服务器和不同结构主机的文件,对客户端在使用上来说是完全透明的。 NFS设置工具的主要功能即提供图形化操作界面,用户可以在这里方便地安装和卸除NFS目录。
  • 1004. (5) 网络文件系统服务器(NFSD)设置 这个设置工具针对NFS服务器端的管理设置。当你的主机是一部可供他人使用本地文件系统的服务器时,此工具提供方便的操作界面,帮助你设置NFS服务器。 在此工具中用户可以开放和关闭NFS目录。 (6) Samba设置 Samba是文件服务器的一种,作用类似于Windows系列的网络邻居沟通来达成文件共享的功能。本程序可设置以下功能: · 设置共享的目录 · 设置共享的打印机 · 删除共享的目录
  • 1005. 15.6 小结 在这一章,我们主要介绍了XWindow系统的基本结构和工作原理,讨论了如何建立和配置一个XWindow系统,以及如何使用XWindow系统,包括启动XWindow系统,XWindow上的桌面管理器的使用,还有XLinux自带的一个配置工具Genie的使用。 在这一章的学习中,希望明确几点: (1) XWindow是一个网络图形系统,是一个客户机/服务器系统。其中显示部分是服务器,X应用程序部分是客户机,所以一般来说服务器是在本地运行而客户机是在远程或者本地运行,这与一般的客户机/服务器模型可能有些不一样。
  • 1006. (2) 在Linux下,XWindow系统的配置文件都是文本文件,没有注册表或者类似的东西。所有配置的改变都可以不通过工具而手动改变配置文件来完成,其效果是一样的。所以有必要了解配置文件中的指令。要记住,配置工具只是让你的工作更轻松,它并不是必需的。 (3) KDE和GNOME以及其他的窗口管理程序或者窗口环境都是XWindow系统的客户端,XWindow系统的服务端是不关心显示的内容的,它只根据X客户的指令来绘图。
  • 1007. (4) 如果你是一个新手,在利用各种配置工具如XLinux的Genie的时候,别忘了顺便了解一下它实际上做了什么事情。它只是个工具,它能干的事情你手动也应该能干。这样才会对你的水平有促进作用。 最后需要说明的是X的工作非常灵活,实际上还可以在自己的工作站上安装一个X Server,而通过在Linux上启动X Client,同样可以达到在远端显示的效果,不过服务器方却不是由服务器来运行的。
  • 1008. 习题 15-1 试着用Genie改变显示器的配置,然后对比XFreeconfig文件的变化。 15-2 查阅资料,写一篇关于X客户端/服务器工作原理的报告,要求对比X服务器分别安装在服务器端和客户端的两种情况下的工作模式。
  • 1009. Linux公社(LinuxIDC.com)Linux公社(LinuxIDC.com)于2006年9月25日注册并开通网站,Linux现在已经成为一种广受关注和支持的一种操作系统,IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教程、Linux认证、SUSE Linux、Android、Oracle、Hadoop等技术。