精通Linux(第2版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-26 21:23:16

点击下载

作者:沃德(Brian Ward)

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

精通Linux(第2版)

精通Linux(第2版)试读:

前言

之所以写这本书,是因为我觉得你应该对你使用的计算机有所了解。你应该可以让软件去做你想让它去做的事(当然要在它的能力范围之内)。要做到这一点,关键是必须理解软件能做什么,以及是怎么做的。这些正是本书要介绍的内容。这样你就不必对着计算机抓狂了。

如果你要学习这方面的知识,Linux是一个很好的平台,因为它是一个透明的系统。特别是大多数系统配置都存放在文本文件中,让人一目了然。难点在于了解每个组件分别负责什么,以及它们如何协同工作。

读者对象

我们学习Linux的原因可能各不相同。对于IT从业者(如系统运维人员)来说,他们需要了解本书中的几乎所有内容。对于Linux软件架构师和开发人员来说,他们同样需要了解这些内容,以便发挥操作系统的最大功效。对于只需考虑个人所用Linux系统的研究人员和学生来说,本书能够让他们理解为什么系统是那个样子的。

还有一些堪称多面手的读者,出于兴趣、谋利或其他原因而摆弄计算机,喜欢探究事情的根源,喜欢尝试不同的可能性。或许你就是其中一位。

阅读要求

虽然开发人员热爱Linux,不过并非开发人员才能阅读本书,只要你有一些基础的计算机知识即可。也就是说,你需要知道如何操作GUI(特别是能看懂各种Linux发行版的安装和配置界面),需要知道什么是文件什么是目录(文件夹)。此外,还要有心理准备随时查看系统文档或者上网搜索一些相关文章。当然,我前面提过,最重要的是你对电脑的热情。

阅读方法

要对任何技术建立起系统的认识都不是件容易的事。而说到软件系统的工作原理,就更复杂了。有时候面对大量的技术细节,读者会难以抓住重点(因为人类大脑无法同时处理太多新概念),但是如果解释得不够透彻,又会让读者一知半解,不利于后面的学习。

本书每一章都会先介绍最重要最基本的知识,以便让读者能够继续深入。为了突出重点,有些地方简化了很多内容。随着一章内容的展开,更多细节才会在最后几节出现。这些内容需要你马上就掌握吗?通常不用,我经常也会这么提醒你。如果你觉得正在阅读的内容有些枯燥难懂,可以随时跳到下一章或者稍事休息。

动手操作

你最好准备一台可以用来实际操作的Linux计算机。你可以使用虚拟机,比如我就使用VirtualBox来测试本书中的很多实例。你需要拥有超级用户(root)权限,不过多数情况下你需要以普通用户身份登录系统。我们将主要通过终端窗口或者远程会话来运行命令行。如果你之前毫无经验也无大碍,书中第2章会让你尽快上手。

书中的命令通常是像下面这样:$ ls /[输出结果]

你只需输入第一行粗体的文本,非粗体的文本是系统的输出结果。$是普通用户提示符。如果你是超级用户的话则是#。(详见第2章。)

本书结构

本书分为三个部分。第一部分整体介绍Linux系统以及运行Linux系统所需的常用工具和命令。随后我们会根据系统启动的大体顺序,更深入地介绍从设备管理到网络配置的各个部分。最后我们会演示系统各部分的运行方式,并介绍一些基本技巧和开发人员常用的工具。

除第2章以外,开始的几章均主要讲解Linux内核,然后逐步涉及用户空间。(如果你现在对我所说的一头雾水也没关系,我们将在第1章中介绍这些概念。)

本书的内容尽量保证对各个版本的Linux系统均适用。但要涵盖各个系统之间的差异也实在是项繁琐的工作,所以我尽量考虑两个主要的Linux版本:Debian(包括Ubuntu)和RHEL/Fedora/CentOS。本书主要针对的是桌面和服务器系统。嵌入式系统(如Android和OpenWRT)也多有涉及,但各系统之间的差异还需要你自己去探索。

第2版的新内容

本书的第1版侧重于从用户的角度来介绍Linux系统,旨在帮助读者了解系统各部分的工作原理。彼时Linux上的软件安装和配置还不是那么容易。

有幸的是,随着各种新版本的出现,这些问题已然不复存在,所以我剔除了一些较为陈旧和不太相关的内容(比如打印),以便能够更加深入地介绍Linux内核。你可能没有意识到你将会多么频繁地和内核打交道。

当然,上一版中的很多内容随着时间推移也发生了较大变化,我花了大量的精力梳理和更新了它们,特别是在Linux的启动和设备管理方面。我对很多内容也进行了重新组织,以满足当下读者的阅读兴趣与需要。

本书没有发生变化的是它的厚度。我希望读者能够尽快上手,因此会解释一些不太容易理解的细节,但我又不想让这本书变得你拿都拿不动。只要掌握了本书介绍的知识,自己再去深入探索就不是一件难事了。

我还删掉了第1版中一些关于历史背景的介绍,目的是突出重点。如果你对Linux和Unix的历史感兴趣,可以参考Peter H. Salus所著The Daemon, the Gnu, and the Penguin(Reed Media Services,2008),这本书详细介绍了我们使用的各种软件的历史沿革。

关于术语

关于操作系统中某些组件应该叫什么,一直都存在争论。甚至“Linux”是否应该叫作“GNU/Linux”也存在争论,因为其中使用了GNU项目的成果。本书中我们尽量使用通用术语,不使用拗口、生硬的词汇。

致谢

感谢以下对本书的第1版提供过帮助的人:James Duncan、Douglas N. Arnold、Bill Fenner、Ken Hornstein、Scott Dickson、Dan Ehrlich、Felix Lee、Scott Schwartz、Gregory P. Smith、Dan Sully、Karol Jurado以及Gina Steele。在第2版的写作中,我要特别感谢Jordi Gutiérrez Hermoso卓越的技术审阅工作,他为本书提供了极有价值的建议和勘误。还要感谢Dominique Poulain和Donald Karon,他们在本书写作期间就给出了非常好的反馈意见,还要感谢Hsinju Hsieh在我写作这本书期间对我的宽容。

最后,我还要感谢本书策划编辑Bill Pollock、项目编辑Laurel Chun,以及No Starch Press出版社的Serena Yang、Alison Law和其他人为本书面世所做的一如既往的卓越工作。

第一版书评

“非常棒的书。在近350页的内容中涵盖了Linux的所有基础知识。”——EWEEK“对于那些想要学习Linux,同时对操作系统内部工作原理又不太熟悉的读者,本书绝对值得推荐。”——O’REILLYNET“介绍Linux基础知识最好的书之一,同时也适合Linux高级用户阅读,五星。”——OPENSOURCE-BOOK-REVIEWS.COM“本书的成功源于它对内容的良好组织和对技术细节的深入探讨。”——KICKSTART NEWS“本书对Linux的介绍可谓标新立异。它朴实无华,注重对命令行的介绍,并且深入到系统内部,而非仅仅停留在图形用户界面。”——TECHBOOKREPORT.COM“本书很好地介绍了Linux系统的工作原理。”——HOSTING RESOLVE第1章概述乍看起来,Linux这样的现代操作系统非常复杂,内部有多得令人眼花缭乱的各种组件在同步运行和相互通信。比如:Web服务器可以连接到数据库服务器,还有可能用到很多其他程序也在使用的公共组件。那么,整个系统究竟是怎样运作的呢?

理解操作系统工作原理最好的方法是抽象思维,换句话说,你可以暂时忽略大部分细节。就像坐车一样,通常你不会去在意车内固定发动机的装配螺栓,也不会关心你走的路是谁修筑的。如果你是一个乘客的话,你可能只关心车要做的事情(比如车要把你带到哪)以及车的一些基本操作(比如如何打开车门、怎样系好安全带)。

但如果你在开车的话,就需要了解更多的细节,比如如何控制油门、怎样换挡,还有如何处理意外情况。

如果我们觉得开车这个事情太复杂,就可以运用“抽象思维”来帮助理解。首先你可以将“一辆汽车在路上行驶”抽象为三个部分:汽车、道路和驾驶操作。这样有助于将复杂的问题分解开来。如果道路颠簸,你不会去埋怨车辆本身和你的驾驶技术。相反,你可能会问为什么这条路这么烂,或者如果这是条新修的路的话,那么筑路工人的活干得可真够差劲的。

软件开发人员运用抽象思维来开发操作系统和应用程序。在计算机软件领域有许多术语来描述抽象的子系统,如子系统、模块和包等。本书中我们使用组件这个相对简单的词。在软件开发过程中,开发人员通常不用太关心他们需要使用的组件的内部结构,他们只关心能使用哪些组件,以及怎么个用法。

本章概述了Linux操作系统涉及的主要组件。虽然每一个组件都包含纷繁复杂的技术细节,但我们将暂时忽略这些细节,而专注于这些组件在系统中发挥的功能。1.1 Linux 操作系统中的抽象级别和层次

在组织得当的前提下,通过抽象将系统分解为组件有助于我们了解其工作机制。我们将组件划分为层次或级别。组件的层次(或级别)代表它在用户和硬件系统之间所处的位置。Web浏览器、游戏等应用处于最高层,底层则是计算机硬件系统,如内存。操作系统处于这两层之间。

Linux操作系统主要分为三层。如图1-1所示,最底层是硬件系统,包括内存和中央处理器(用于计算和从内存中读写数据),此外硬盘和网络接口也是硬件系统的一部分。

硬件系统之上是内核,它是操作系统的核心。内核是运行在内存中的软件,它向中央处理器发送指令。内核管理硬件系统,是硬件系统和应用程序之间进行通信的接口。

进程是指计算机中运行的所有程序,由内核统一管理,它们组成了最顶层,称为用户空间(user space)。(另一个更确切的术语是用户进程,无论它们是否直接和用户交互。例如,所有的Web服务器都是以用户进程的形式运行的。)

图1-1 Linux系统的基本组成

内核和用户进程之间最主要的区别是:内核在内核模式(kernel mode)中运行,而用户进程则在用户模式(user mode)中运行。在内核模式中运行的代码可以不受限地访问中央处理器和内存,这种模式功能强大,但也非常危险,因为内核进程可以轻而易举地使整个系统崩溃。那些只有内核可以访问的空间我们称为内核空间(kernel space)。

相对于内核模式,用户模式对内存和中央处理器的访问有一定程度的限制,可访问的内存空间通常很小,对CPU的操作也很安全。用户空间指的是那些用户进程能够访问的内存空间。如果一个用户进程出错并崩溃的话,其导致的后果也相对有限,并且能够被内核清理掉。例如,如果你的Web浏览器崩溃了,不会影响到你正在运行的其他程序。

理论上来说,一个用户进程出问题并不会对整个系统造成严重的影响。当然这取决于我们如何定义“严重的影响”,并且还取决于该进程拥有的权限。因为不同的进程拥有的权限可能不同,一些进程能够执行一些别的进程无权执行的操作。举个例子,如果拥有足够的权限,用户进程可以将硬盘上的数据全部清除。也许你会觉得这样太危险,但好在操作系统提供了一些相关的安全措施,而且大多数用户进程并没有这个权限。1.2 硬件系统:理解主内存

主内存(main memory)或许是所有硬件系统中最为重要的部分。基本上来讲,主内存存储0和1这样的数据。我们将每个0和1称为一个比特(或位,bit)。内核和进程就在主内存中运行,它们就是一系列比特的大合集。所有外围设备的数据输入和输出都通过主内存完成,同样是以一系列0和1的形式。中央处理器像一个操作员一样处理内存中的数据,它从内存读取指令和数据,然后将运算结果写回内存。

在我们谈论内存、进程、内核和其他内容时,你会经常看到状态(state)这个词。严格说来,一个状态就是一组特定排列的比特。例如,内存中0110、0001和1011这三组比特值即表示三个不同的状态。

一个进程动辄由几百万个比特值组成,因而使用抽象词汇来描述状态可能比使用比特值更简单一些。我们可以使用进程已经完成的任务或者当前正在执行的任务来描述其状态,如“进程正在等待用户输入”或者“进程正在执行启动任务的第二个阶段”。注解:我们通常使用抽象词汇而非比特值来描述状态,映像(image)这个词用来表示比特值在内存中的特定物理排列。1.3 内核

我们之所以介绍主内存和状态,是因为内核的几乎所有操作都和主内存相关。其中之一是将内存划分为很多区块,并且一直维护着这些区块的状态信息。每一个进程拥有自己的内存区块,且内核必须确保每个进程只使用它自己的内存区块。

内核负责管理以下四个方面。● 进程:内核决定哪个进程可以使用CPU。● 内存:内核管理所有的内存,为进程分配内存,管理进程间的共

享内存以及空闲内存。● 设备驱动程序:作为硬件系统(如磁盘)和进程之间的接口,内

核负责操控硬件设备。● 系统调用和支持:进程通常使用系统调用和内核进行通信。

下面我们详细介绍一下这四个方面。注解:如果你对内核的详细工作原理感兴趣,可以参考Abraham Silberschalz、Peter B. Galvin和Greg Gagne所著Operating System Concepts, 9th Edition(Wiley,2012),以及Andrew S. Tanenbaum和Herbert Bos所著Modern Operating Systems, 4th Edition(Prentice Hall,2014)这两本书。1.3.1 进程管理

进程管理涉及进程的启动、暂停、恢复和终止。启动和终止进程比较直观,但是要解释清楚进程在执行过程中如何使用CPU则相对复杂一些。

在现代操作系统中,很多进程貌似都是“同时”运行的。例如,你可以同时在桌面打开Web浏览器和电子表格应用程序。然而,虽然它们表面上看是同时运行,但实际上这些应用程序背后的进程并不完全是同时运行的。

我们设想一下,在只有一个CPU的计算机系统中,可能会有很多进程可以使用CPU,但是在任何一个特定的时间段内只能有一个进程可以使用CPU。所以实际上是多个进程轮流使用CPU,每个进程使用一段时间后就暂停,然后让另一个进程使用,依次轮流,时间单位是毫秒级。一个进程让出CPU使用权给另一个进程称为上下文切换(context switch)。

进程在其时间段内有足够的时间完成主要的计算工作(实际上,进程通常在单个时间段内就能完成它的工作)。由于时间段非常短,短到我们根本察觉不到,所以在我们看来,系统是在同时运行多个进程(我们称之为多任务执行)。

内核负责上下文切换。我们来看看下面的场景,以便理解它的工作原理。

1. CPU为每个进程计时,到时即停止进程,并切换至内核模式,由内核接管CPU控制权。

2. 内核记录下当前CPU和内存的状态信息,这些信息在恢复被停止的进程时需要用到。

3. 内核执行上一个时间段内的任务(如从输入输出设备获得数据,磁盘读写操作等)。

4. 内核准备执行下一个进程,从准备就绪的进程中选择一个执行。

5. 内核为新进程准备CPU和内存。

6. 内核将新进程执行的时间段通知CPU。

7. 内核将CPU切换至用户模式,将CPU控制权移交给新进程。

上下文切换回答了一个十分重要的问题,即内核是在什么时候运行的。答案就是,内核是在上下文切换时的时间段间隙中运行的。

在多CPU系统中,情况要稍微复杂一些。如果新进程将在另一个CPU上运行,内核就不需要让出当前CPU的使用权。不过为了将所有CPU的使用效率最大化,内核会使用一些其他的方式来获取CPU控制权。1.3.2 内存管理

内核在上下文切换过程中管理内存,这是一项十分复杂的工作,因为内核要保证以下所有条件:● 内核需要自己的专有内存空间,其他的用户进程无法访问;● 每个用户进程有自己的专有内存空间;● 一个进程不能访问另一个进程的专有内存空间;● 用户进程之间可以共享内存;● 用户进程的某些内存空间可以是只读的;● 通过使用磁盘交换,系统可以使用比实际内存容量更多的内存空

间。

新型的CPU提供了MMU(Memory Management Unit,内存管理单元),MMU使用了一种叫作虚拟内存的内存访问机制,即进程不是直接访问内存的实际物理地址,而是通过内核使得进程看起来可以使用整个系统的内存。当进程访问内存的时候,MMU截获访问请求,然后通过内存映射表将要访问的内存地址转换为实际的物理地址。内核需要初始化、维护和更新这个地址映射表。例如,在上下文切换时,内核将内存映射表从被移出进程转给被移入进程使用。注解:内存地址映射通过内存页面表(page table)来实现。

关于内存性能,我们将在第8章详细介绍。1.3.3 设备驱动程序和设备管理

对于设备来说,内核的角色比较简单。通常设备只能在内核模式中被访问(例如用户进程请求内核关闭系统电源),因为设备访问不当有可能会让系统崩溃。另一个原因是不同设备之间没有一个统一的编程接口,即使同类设备也如此,比如两个不同的网卡。所以设备驱动程序传统意义上来说是内核的一部分,它们尽可能为用户进程提供统一的接口,以简化开发人员的工作。1.3.4 系统调用和系统支持

内核还对用户进程提供其他功能。例如,系统调用(system call或syscall)为进程执行一些它们不擅长或无法完成的工作。打开、读取和写文件这些操作都涉及系统调用。

fork()和exec()这两个系统调用对于我们了解进程如何启动很重要。● fork():当进程调用fork()时,内核创建一个和该进程几乎一模一

样的副本。● exec():当进程调用exec(program)时,内核启动program来替换

当前的进程。

除了init(参见第6章)以外,Linux中的所有用户进程都是通过fork()来启动的。除了创建现有进程的副本外,大多数情况下你还可以使用exec()来启动新的进程。一个简单的例子是你在命令行运行ls命令来显示目录内容。当你在终端窗口中输入ls时,终端窗口中的shell调用fork()创建一个shell的副本,然后该副本调用exec(ls)来运行ls。图1-2显示启动ls这样的命令时进程和系统调用的流程。

图1-2 新进程的启动注解:系统调用通常使用括号来标记。图1-2中,进程请求内核使用fork()系统调用创建一个新的进程。这样的标记来源于C编程语言。阅读本书你不需要有C语言的知识,只需要记住系统调用是进程和内核之间的交互方式。此外,本书中我们简化了很多系统调用。例如exec()实际上是一系列具有相似功能的系统调用,只是代码实现有所不同。

除了传统的系统调用,内核还为用户进程提供其他很多功能,最为常见的是虚拟设备。虚拟设备对于用户进程而言是物理设备,但其实它们都是通过软件实现的。因此从技术角度来说,它们并不需要存在于内核中,但是实际上它们很多都存在于内核中。例如:内核的随机数生成器(/dev/random)这样的虚拟设备,如果由用户进程来实现,难度要大很多。注解:从技术上说,用户进程还是需要通过使用系统调用打开设备的方式来访问虚拟设备,所以进程总是避免不了要和系统调用打交道。1.4 用户空间

前面提到过,内核分配给用户进程的内存我们称之为用户空间。因为一个进程简单说就是内存中的一个状态。用户空间也可以指所有用户进程占用的所有内存。(用户空间还有一个不太正式的名称,叫userland。)

Linux中大部分的操作都发生在用户空间中。虽然从内核的角度来说所有进程都是一样的,但是实际上它们执行的是不同的任务。相对于系统组件,用户进程位于一个基础服务层中。图1-3就展示了一组组件在Linux系统中是如何交互工作的。其中最底层是基础服务层,工具服务在中间,用户使用的应用程序在最上层。图1-3是一个简化版本,你可以看到顶层距离用户最近(如用户接口和Web浏览器)。中间一层中有邮件服务器这样的组件供Web浏览器使用。最下层是一些更小的服务组件。

图1-3 进程类型和相互间的交互

最下层通常是由一些小的组件组成,它们比较精巧,专注完成某一个特定功能。中间层的组件比较大一些,如邮件、打印和数据库服务。顶层组件完成用户交互和复杂的功能。组件之间也可以相互调用。如果组件A调用了组件B的功能,我们可以视为组件A和B在同一层级,或者B在A之下。

然而,图1-3只是一个粗略图,实际上用户空间里没有很明显的界限。例如许多应用程序和服务会将系统诊断信息写入日志,大部分程序使用标准的系统日志服务来完成,但也有一些程序是自己实现日志功能。

此外,很多用户空间组件比较难分类,像Web服务器和数据库服务器这样的服务组件,你可以认为它们在图1-3中属于高级别组件,因为它们复杂度很高。然而用户应用程序也会经常调用它们的功能,所以你也可以将它们归入中级别组件。1.5 用户

Linux内核支持用户这一Unix的传统概念。一个用户代表一个实体,它有权限运行用户进程,对文件拥有所有权。每个用户都有一个用户名,如billyjoe。然而内核是通过用户ID来管理用户的,用户ID是一串数字标识(详见第7章)。

用户机制主要用于权限管理。每一个用户进程都有一个用户作为所有者,我们称其为以该用户运行的进程。在一定限制条件下,用户可以终止和改变他的进程的行为。但是对其他用户的进程无权干预。此外,用户可以决定是否将属于自己的文件和其他用户共享。

Linux操作系统的用户包括系统自带用户和供人使用的用户。详情见第3章。其中最关键的用户是root用户(意思是根用户或超级用户)。root用户不受前面提到的种种权限的限制,它可以终止其他用户的进程,读取系统中的任何文件。因此root也被称作超级用户。Unix的系统管理员拥有超级用户权限。注解:使用root权限操作系统是一件很危险的事情,因为用户拥有最高权限,可以为所欲为,一旦出错很难定位和恢复。因此系统管理员通常尽量避免使用root权限。而且,root用户虽然权限很高,但是还是在用户模式而非内核模式中运行。

用户组是指一组用户的集合。用户组的主要作用是允许一个用户同组内的其他用户共享文件权限。1.6 前瞻

至此我们对Linux系统的组成有了一个大致的了解。用户和用户进程交互,内核管理进程和硬件系统。内核和进程都在内存中运行。

这些基础知识固然很重要,但如果想要了解更多的细节,你需要实际操作一番。下一章你会了解到一些用户空间的基础知识,还有本章没有提及的永久存储(硬盘、文件等),就是存放应用程序和数据的地方。第2章基础命令和目录结构本章我们将介绍Unix系统的命令和工具,它们在本书中会经常被用到。你可能已经对这些基本知识有所了解,不过我还是建议你花些时间再阅读一遍,特别是2.19节关于目录结构的阐述。

你也许会问,为什么要介绍Unix命令?这本书不是关于Linux的吗?没错,Linux其实是Unix的一个变种,它的本质还是Unix。Unix这个词在本章中出现的频率甚至高于Linux,并且你可以将本章的知识直接应用到其他基于Unix的操作系统,如Solaris和BSD。我们尽量避免介绍太多Linux特有的内容,一方面可以让你多了解一点其他的操作系统,另一方面也因为那些只对Linux适用的扩展功能往往不太稳定可靠。掌握核心命令能够让你很快上手任何新的基于Linux的操作系统。注解:Unix初学者若想了解更多细节,可以参考这几本书:The Linux Command Line(No Starch Press,2012)、UNIX for the Impatient(Addison-Wesley Professional,1995)和Learning the UNIX Operating System , 5th edition(O'Reilly,2001)。2.1 Bourne shell: /bin/sh

shell意思为命令行界面,是Unix操作系统中最为重要的部分之一。shell是运行命令行的应用程序,而命令行就是用户输入的那些命令。同时它为Unix程序员提供了一个小的编程环境,在这里Unix程序员可以将通用的任务分解为一些小的组件,然后使用shell来管理和组织它们。

Unix操作系统中很多重要的部分其实都是shell脚本,它们是包含一系列shell命令的文本文件。如果你用过MS-DOS,你可以将shell脚本理解为功能强大的.bat批处理文件。我们将在第11章详细介绍shell脚本。

通过本书的阅读和练习,你将会逐渐熟练地使用shell来运行各种命令。它的一个好处是一旦出现了误操作,你可以清楚地看到你的输入错误,然后进行修正。

Unix的shell有很多种,它们都是基于Bourne shell(/bin/sh)这个贝尔实验室开发的标准shell,在早期的Unix系统上运行。所有基于Unix的操作系统都需要Bourne shell才能正常工作。

Linux使用了一个增强版本的Bourne shell,我们称之为bash或者“Bourne-again” shell。大部分Linux系统的默认shell是bash,其通常有一个符号链接/bin/sh。你需要使用bash来运行本书中的例子。注解:你的Unix系统管理员为你设置的默认shell可能不是bash,你可以使用chsh命令来更改,或者请管理员为你更改。2.2 shell的使用

安装Linux时,除了默认的root账号外,你还需要为自己创建至少一个普通用户账号,这些账号将会是你的个人账号。本章中你需要使用普通用户账号。2.2.1 shell窗口

登录系统后,打开一个shell窗口(也叫作终端窗口)。打开shell窗口最简单的方法是,在Gnome或者Ubuntu Unity这样的图形用户界面(Graphical User Interface,以下简称GUI)中运行终端程序,这样就可以在新的窗口中启动shell。通常在窗口的顶端你能看到一个$提示符。在Ubuntu上,提示符是这样:name@host:path$(用户名@主机名:路径$)。在Fedora上,提示符是这样:[name@host path]$。shell窗口类似Windows上的DOS,OS X系统上的终端程序本质上和Linux中的shell窗口一样。

本书中的很多命令都可以在shell上运行,例如你可以输入以下命令行(不用输入前面的$),然后按回车键:$ echo Hello there.注解:本书中许多shell命令都以#开头,需要以root身份来运行,运行时需要格外小心。

现在试试下面这个命令:$ cat /etc/passwd

这个命令是将文件/etc/passwd中的内容显示到shell窗口中。有关这个文件的内容我们会在第7章详细介绍。2.2.2 cat命令

cat命令很简单,它显示一个或者多个文件的内容,命令语法如下:$ catfile1 file2 ...

上面这个cat命令会显示file1和file2等文件的内容,然后退出。之所以叫cat是因为如果有多个文件的话,它会把这些文件的内容拼接起来显示。2.2.3 标准输入输出

我们将使用cat命令来学习Unix的输入和输出(以下简称I/O)。Unix进程使用I/O流来读写数据。进程从输入流中读取数据,向输出流写出数据。数据流非常灵活,比如输入流可以是文件、设备、终端,甚至还可以是来自其他进程的输出流。

想知道输入流的工作原理,只需要输入cat命令并回车,这时候你会看到屏幕上没有显示任何结果,因为cat命令仍在运行中。现在你输入几个字符然后回车,你会看到cat命令会在屏幕上显示出你刚刚输入的字符。最后你可以在任意空白行按CTRL-D终止cat命令的执行并回到shell提示符。

你刚刚和cat命令进行的一系列交互就是通过数据流机制来实现的。因为你没有指定输入文件名,cat命令就从Linux内核提供的默认标准输入流中获得输入数据,这时运行cat命令的终端就成为标准输入。注解:按CTRL-D终止当前终端的标准输入并终止命令(通常会终止一个程序)。这和CTRL-C不一样。CTRL-C是终止当前进程的运行,无论是否有输入和输出。

标准输出也与之类似。内核为每个进程提供一个标准输出流供它们输出数据。cat命令在终端运行的时候,标准输出就和该终端建立连接,cat命令将数据输出到标准输出,就是你在屏幕上看到的结果。

标准输入和标准输出通常简写为stdin和stdout。很多命令和cat一样,如果你不为它们指定输入文件,他们就从标准输入获得数据。输出则有点不同,一部分命令(如cat)将数据输出到标准输出,另一部分命令可以将数据直接输出到文件。

除了标准输入和输出外,还有标准错误信息流,我们将在2.14.1节介绍。

标准流的一个优点是你可以随心所欲地指定数据的输入输出来源,在2.14节中我们会介绍如何将流连接到文件和其他进程。2.3 基础命令

本节将介绍更多的Unix命令。它们大都需要输入参数,同时支持可选项和格式(由于数量太多,在此不一一列出)。下面是一些基础命令的简单介绍,我们暂不深入讲解。2.3.1 ls命令

ls命令显示指定目录的内容,默认参数为当前目录。ls -l显示详细的列表,ls -F显示文件类型信息(文件类型和权限将在2.17节介绍)。下面是文件详细列表的一个示例,其中第三列是文件的所有者,第四列是用户组,第五列是文件大小,后面是文件更改的时间、日期以及文件名。$ ls -ltotal 3616 -rw-r--r-- 1 juser users 3804 Apr 30 2011 abusive.c-rw-r--r-- 1 juser users 4165 May 26 2010 battery.zip-rw-r--r-- 1 juser users 131219 Oct 26 2012 beav_1.40-13.tar.gz-rw-r--r-- 1 juser users 6255 May 30 2010 country.cdrwxr-xr-x 2 juser users 4096 Jul 17 20:00 cs335-rwxr-xr-x 1 juser users 7108 Feb 2 2011 dhry-rw-r--r-- 1 juser users 11309 Oct 20 2010 dhry.c-rw-r--r-- 1 juser users 56 Oct 6 2012 doitdrwxr-xr-x 6 juser users 4096 Feb 20 13:51 dwdrwxr-xr-x 3 juser users 4096 May 2 2011 hough-stuff

第一列中的d我们将在2.17节详细介绍。2.3.2 cp命令

cp命令用来复制文件。下面的命令将文件file1复制到文件file2:$ cp file1 file2

下面的命令将多个文件(file1 ... fileN)复制到目录dir:$ cp file1 ... fileN dir2.3.3 mv命令

mv命令有点类似cp,用来重命名文件。下面的命令将文件名从file1重命名为file2:$ mv file1 file2

你也可以使用mv将多个文件移动到某个目录:$ mv file1 ... fileN dir2.3.4 touch命令

touch命令用来创建文件。如果文件已经存在,则该命令会更新文件的时间戳,就是我们在ls -l命令的执行结果中看到的文件更新时间和日期。下面的命令创建一个新的文件,内容为空:$ touch file

如果我们对文件执行ls -l,你将会看到下面的显示结果,其中➊就是文件被创建的时间和日期:$ ls -l file-rw-r--r-- 1 juser users 0 May 21 18:32➊ file2.3.5 rm命令

rm命令用来删除文件,文件一旦被删除通常无法恢复:$ rm file2.3.6 echo命令

echo命令将它的参数显示到标准输出,例如:$ echo Hello again.Hello again.

我们在查看shell通配符展开(如*这样的通配符)和环境变量(如$HOME)的时候经常使用echo命令,本章稍后会详细介绍。2.4 浏览目录

Unix的目录结构是从/开始,有时候也叫作root目录。目录之间使用斜杠/分隔,而不是Windows中的反斜杠\。root目录/下有子目录,如/usr,详见2.19节。

我们通过路径或路径名来访问文件。以/开头的路径(如/usr/lib)叫绝对路径。

两个点(..)代表一个目录的上层目录。如果你当前在目录/usr/lib中,那..就代表/usr目录,../bin则代表/usr/bin。

一个点(.)代表当前目录。如果你当前在/usr/lib目录中,.就代表/usr/lib,./X11则代表/usr/lib/X11。通常我们不需要使用.,而是直接使用目录名来访问当前目录下的子目录,如X11效果和./X11一样。

不以/开头的路径叫相对路径,我们大部分时候都基于当前所在目录使用相对路径。下面介绍一些和目录操作相关的命令。2.4.1 cd命令

cd命令用来设置当前工作目录。当前工作目录是指你的进程和shell当前所在的目录。$ cd dir

如果不带dir参数,cd命令会返回你的个人主目录,指的是你登录系统后进入的目录。2.4.2 mkdir命令

mkdir命令用来创建新目录,例如,下面的命令创建一个名为dir的新目录:$ mkdir dir2.4.3 rmdir命令

rmdir命令用来删除目录:$ rmdir dir

如果要删除的目录里面有内容(文件和其他目录),上面的命令会执行失败。因为rmdir只能删除空目录,你可以使用rm -rf来删除一个目录以及其中的所有内容。使用这个命令的时候要非常小心,尤其是当你是超级用户(root或superuser)的时候。因为-r选项会依次删除dir中的所有文件和子目录,-f选项代表强制删除。所以使用-rf时尽量不要在参数里使用通配符(如*),并且执行命令前最好检查参数是否正确。2.4.4 shell通配符

shell可以使用通配符来匹配文件名和目录名。其他的操作系统也有通配符这个概念。比如*代表任意字符和数字。下面的命令列出当前目录中的所有文件:$ echo *

shell根据参数中的通配符来匹配文件名。shell将命令中的参数替换为实际的文件名,这个过程我们称为展开。比如:● at*展开为所有以at开头的文件名;● *at展开为所有以at结尾的文件名;● *at*展开为所有包含at的文件名。

如果通配符没有匹配的文件名,shell就不进行任何的展开,参数按照原样来执行,比如:echo *dfkdsafh。注解:如果你惯于使用MS-DOS,你可能会下意识地使用*.*来匹配所有文件。在Linux系统和其他Unix系统中,*.*只匹配那些包含.的文件名和目录名,而Unix系统中很多文件名是没有.的。

另外一个shell通配符问号(?)帮助shell确切匹配任意一个字符,如b?at与boat和brat相匹配。

如果不想让shell展开通配符,你可以使用单引号('')。例如运行echo '*'将会显示一个*。在一些命令如grep和find中,这样做非常有用(这一内容将在11.2节详细介绍)。注解:需要注意的是,shell是先展开通配符,然后执行命令行。如果*传递到命令行的时候仍然未能展开,shell则对此无能为力,一切都取决于命令本身如何处理。

现代shell的模式匹配能力并不仅限于此,但*和?这两种是你必须要掌握的。2.5 中间命令

下面我们介绍一些基本的Unix中间命令。2.5.1 grep命令

grep命令显示文件和输入流中和参数匹配的行。如下面的命令显示文件/etc/passwd中包含文本root的所有行:$ grep root /etc/passwd

在对多个文件进行批量操作的时候,grep命令非常好用,因为它显示文件名和匹配的内容。如果你想查看目录/etc中所有包含root的文件,可以执行以下命令:$ grep root /etc/*

grep命令有两个比较重要的选项,一个是-i(不区分大小写),一个是-v(反转匹配,就是显示所有不匹配的行)。grep还有一个功能强大的变种叫作egrep(实际上就是grep -E)。

grep命令能够识别正则表达式。正则表达式比通配符功能更强大,下面是两个例子:● .*匹配任意多个字符(类似*通配符);● .匹配任意一个字符。注解:帮助手册grep(1)中有关于正则表达式的详细说明,不过对于读者来说可能比较不方便理解。你可以参考这两本书:Mastering Regular Expression,3rd edition(O'Reilly,2006)或者Programming Perl,4th edition(O'Reilly,2012)中的“the regular expression”一章。如果你对数学和正则表达式的历史感兴趣,可以参阅Introduction to Automata Theory , Language, and Computation,3rd edition(Prentice Hall,2006)。2.5.2 less命令

当要查看的文件过大或者内容多得需要滚动屏幕的时候,可以使用less命令。如要查看像/usr/share/dict/words这样的大文件,可以使用less /usr/share/dict/words命令。less命令可以将内容分屏显示,按空格键可查看下一屏,B键查看上一屏,Q键退出。注解:less命令实际上是more命令的增强版本。绝大多数Linux系统中都有这个命令,但是一些Unix系统和嵌入式系统中没有这个命令,这时你可以使用more命令。

你可以在less命令的输出结果中进行搜索。例如:使用/word从当前位置向前搜索word这个词,使用?word从当前位置向后搜索。当找到一个匹配的时候,按N键可以跳到下一个匹配。

你可以将几乎所有进程的输出作为另一个进程的输入,我们将在2.14节详细介绍。当你执行的命令涉及很多输出,或者你想使用less来查看输出结果的时候,这个方法非常管用,比如下例所示:$ grep ie /usr/share/dict/words | less

你可以自己亲身实践一下这个命令。类似这样的less代码你会常用到。2.5.3 pwd命令

pwd命令仅输出当前的工作目录名。这个命令看上去不是那么有用,其实不然,它有以下两个用处。

首先,并不是所有的提示符都显示当前目录名,甚至有时候你需要摆脱它,因为它占用很大空间,这时候就需要使用pwd来解决。

其次,使用符号链接(我们将在2.17.2节介绍)的时候通常很难获知当前目录信息,这时我们可以使用pwd -P来查看。2.5.4 diff命令

diff命令用来查看两个文件之间的不同,例如:$ diff file1 file2

该命令有几个选项可以让你设置输出结果的格式,不过默认的格式对于我们来说已经足够清晰易读了。很多开发人员喜欢用diff -u格式,因为这个格式能被许多自动化工具很好地识别。2.5.5 file命令

如果你想知道一个文件的格式信息,可以执行file命令:$ file file

这个看似平淡无奇的命令会给你提供很多有用的信息。2.5.6 find和locate命令

我们有时候会碰到一种让人抓狂的情况,就是明明知道有那么一个文件,但就是不知道它在哪个目录。别急,使用find命令可以帮你在目录中寻找文件:$ find dir -name file -print

find命令能做很多事情,但是在你确定你了解-name和-print选项之前,不要尝试诸如-exec这样的选项。find命令可以使用模式匹配参数(如*),但是必须加引号('*'),以免shell自动将它们展开。(回想2.4.4节讲的,shell在运行命令前会展开通配符。)

另外一个查找文件的命令是locate。和find不同的是,locate在系统创建的文件索引中查找文件。这个索引由操作系统周期性地进行更新,查找速度比find更快。但是locate对于查找新创建的文件可能会无能为力,因为它们有可能还没有被加入到索引中。2.5.7 head和tail命令

head命令显示文件的前10行内容(例如head /etc/passwd)。tail命令显示文件的最后10行内容(如tail /etc/passwd)。

你可以使用-n选项来设置显示的行数(例如:head -5 /etc/passwd)。如果要从第n行开始显示所有内容,使用tail +n。2.5.8 sort命令

sort命令将文件内的所有行按照字母顺序快速排序。你可以使用-n选项按照数字顺序排序那些以数字开头的行。使用-r选项反向排序。2.6 更改密码和shell

你可以使用passwd命令来更改密码,你需要输入一遍你的旧密码和两遍新密码。密码最好复杂一些,不要使用简单的词句,最好是数字、大小写字母和特殊字符混合。

设置密码的一个好方法是选择一个你能记住的短句,将其中的某些字符替换为数字和标点,然后将这个密码记牢。

你可以用chsh命令更改shell(如改为ksh或tcsh)。本书默认使用的shell是bash。2.7 dot文件

现在跳转到你的home目录,分别运行ls和ls -a两个命令,你应该能够注意到一些区别。如果没有-a选项,你无法看到那些叫作dot文件的配置文件,这些文件以.开头。常见的dot文件有.bashrc和.login,还有以.开头的dot目录,如.ssh。

这些dot文件没有什么特别之处。有些命令不显示它们是为了让你的个人主目录显得更简洁。例如,除非使用-a选项,否则ls命令不显示dot文件。此外,shell通配符不匹配dot文件,除非明确指定.*。注解:在通配符中使用.*可能会导致一些问题,因为.*匹配.和..(当前目录和上级目录)。你可以使用正则表达式.[^.]*或.??*来排除这两个目录。2.8 环境变量和shell变量

shell中可以保存一些临时变量,称作shell变量,它们是一些字符值。shell变量可以保存脚本执行过程中的数据,一些shell变量用来控制shell的运行方式(例如,bash shell在显示提示符前会读取变量PS1的值,如果PS1变量中有内容,则将它看作提示符)。

我们使用等号=为shell变量赋值,例如:$ STUFF=blah

以上命令将blah赋值给变量STUFF。我们使用$STUFF来获得该变量的值(例如,尝试一下echo $STUFF这个命令)。我们将在第11章介绍更多的shell变量。

环境变量和shell变量类似,但其不仅仅针对shell。Unix系统中所有的进程都能够访问环境变量。两者最大的区别是shell变量只能被当前的shell访问,在shell中运行的命令则无法访问。而环境变量能够被shell中运行的所有进程访问。

环境变量可以通过export命令来设置。例如,如果想将shell变量$STUFF变成环境变量,可以执行如下命令:$ STUFF=blah$ export STUFF

许多程序使用环境变量作为配置和选项信息。例如,你可以使用LESS这个环境变量来配置less命令的参数(许多命令的帮助手册里都有ENVIRONMENT这一节,教你如何使用环境变量来设置该命令的参数和选项)。2.9 命令路径

PATH是一个特殊的环境变量,它定义了命令路径,或简称为路径。命令路径是一个系统目录列表,shell在执行一个命令的时候,会去这些目录中查找这个命令。比如:运行ls命令时,shell会在PATH中定义的所有目录里查找ls,如果ls出现在多个目录中,shell会运行第一个匹配的程序。

如果你运行echo $PATH,你会看到所有的路径组件,它们之间以冒号(:)分隔。例如:$ echo $PATH/usr/local/bin:/usr/bin:/bin

你可以设置PATH变量,为shell查找命令加入更多的路径。例如,使用以下命令可以将路径dir加入到PATH的最前面,这样shell会先查找dir路径,然后再查找其他路径:$ PATH=dir:$PATH

你也可以将路径加入到PATH变量的最后面,这样shell会最后查找dir路径:$ PATH=$PATH:dir注解:在更改PATH时需要特别小心,因为你有可能会不小心将PATH中所有的路径删除掉。不过也不用太担心,你只需要启动一个新的shell就可以找回原来的PATH。最简单的解决办法是关闭当前的终端窗口并启动一个新的窗口。2.10 特殊字符

在谈论Linux的时候,我们需要了解一些术语。如果你有兴趣了解,可参考“Jargon File” (http://www.catb.org/jargon/html/)或者它的印刷版本The New Hacker’s Dictionary(MIT Press,1996)。

表2-1列出了一些特殊字符,其中很多本章已经介绍过。一些工具,比如Perl编程语言,用到几乎所有这些特殊字符!(请注意这里使用的字符名称是美国英语名称。)表2-1 特殊字符字符名称用途*星号正则表达式,通用字符.句点当前目录,文件/主机名的分隔符!感叹号逻辑非运算符,命令历史|管道命令管道/斜线目录分隔符,搜索命令\反斜线常量,宏(非目录)$美元符号变量符号,行尾'单引号字符串常量`反引号命令替换"双引号半字符串常量^脱字符逻辑非运算符,行头~波浪字符逻辑非运算符,目录快捷方式#井号注释,预处理,替换[ ]方括号范围{ }大括号声明块,范围_下划线空格的简易替代注解:控制键我们通常用^来表示,如^C代表CTRL-C。2.11 命令行编辑

在使用shell时,你应该能注意到可以使用左右箭头来编辑命令行,并且通过上下箭头来查看之前的命令。这是Linux系统的标准操作。

但使用ctrl键来代替箭头键会更加方便。表2-2中的命令是Unix系统的文本编辑标准命令,掌握了这些,你就可以很方便地在任何Unix系统中编辑文本。表2-2 命令行按键按键操作CTRL-B左移光标CTRL-F右移光标CTRL-P查看上一条命令(或上移光标)CTRL-查看下一条命令(或下移光标)NCTRL-A移动光标至行首CTRL-移动光标至行尾ECTRL-删除前一个词WCTRL-删除从光标至行首的内容UCTRL-删除从光标至行尾的内容KCTRL-粘贴已删除的文本(例如粘贴CTRL-U所删除的内容)Y2.12 文本编辑器

说到文本编辑,不得不提文本编辑器。要用好Unix,你必须能够编辑文本文件并且不对其造成损坏。Unix系统使用纯文本文件来保存配置信息(如目录/etc中的文件)。编辑文件并不是难事,但由于要经常性地编辑这些文件,因此你需要一个强大的文本编辑器。

在众多文本编辑器中,你需要掌握vi和Emacs二者之一,它们是Unix系统中约定俗成所用的标准编辑器。很多Unix的大拿们对编辑器的选择很挑剔,但是没关系,你可以自己选择,选择标准就是它对你而言合不合适。● 如果你想要一个万能的编辑器,功能强大,有在线帮助,你可以

试试Emacs。不过它需要你进行一些额外的手动编辑。● 如果想要高效快速,那么vi比较适合你。

有关vi的详细知识可以参考这本书:Learning the vi and Vim Editors: Unix Text Processing, 7th edition(O'Reilly,2008)。关于Emacs你可以参考在线文档Start Emacs:打开Emacs,按CTRL-H,然后按T, 或者参考GNU Emacs Manual(Free Software Foundation,2011)。

其他的编辑器如Pico和myriad GUI editor可能界面会更加友好一些,但是你一旦习惯了vi和Emacs以后,也许就再也不想使用它们了。注解:你在进行文本编辑的时候,可能第一次注意到了终端界面和GUI的区别。vi这样的编辑器运行在终端窗口中,使用标准输入输出界面。GUI编辑器启动自己的窗口并有自己的窗口界面,与终端窗口是相互独立的。Emacs既有终端界面也有图形界面。2.13 获取在线帮助

Linux系统的帮助文档非常丰富。帮助手册提供命令的使用说明。比如你若是想了解ls命令的用法,只需运行:$ man ls

帮助手册旨在提供基础知识和参考信息,有时会有一些实例和交叉索引,但是基本没有那种教程式的文档。

帮助手册会按系统排序方式(如按照字母顺序)列出命令的所有选项,但是不会突出重点(比如那些经常被使用的选项)。如果你有足够的耐性,可以逐个尝试,或者可以问别人。

下面的命令可以帮你借助关键字来查找相关帮助手册:$ man -k keyword

如果你只知道某个功能,但是不知道命令名,你可以很方便地通过关键字来查找。比如你若想使用排序功能,就可以运行下面的命令

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载