第2章 基础命令和目录结构

第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 -l
total 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.c
drwxr-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 doit
drwxr-xr-x  6 juser   users     4096 Feb 20 13:51 dw
drwxr-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 dir

2.3.3 mv命令

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

$ mv file1 file2

你也可以使用mv将多个文件移动到某个目录:

$ mv file1 ... fileN dir

2.3.4 touch命令

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

$ touch file

如果我们对文件执行ls -l,你将会看到下面的显示结果,其中➊就是文件被创建的时间和日期:

$ ls -l file
-rw-r--r-- 1 juser users 0 May 21 18:32➊ file

2.3.5 rm命令

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

$ rm file

2.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 dir

2.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?atboatbrat相匹配。

如果不想让shell展开通配符,你可以使用单引号('')。例如运行echo '*'将会显示一个*。在一些命令如grepfind中,这样做非常有用(这一内容将在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 findlocate命令

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

$ find dir -name file -print

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

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

2.5.7 headtail命令

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(如改为kshtcsh)。本书默认使用的shell是bash

2.7 dot文件

现在跳转到你的home目录,分别运行lsls -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-N

查看下一条命令(或下移光标)

CTRL-A

移动光标至行首

CTRL-E

移动光标至行尾

CTRL-W

删除前一个词

CTRL-U

删除从光标至行首的内容

CTRL-K

删除从光标至行尾的内容

CTRL-Y

粘贴已删除的文本(例如粘贴CTRL-U所删除的内容)

2.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

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

$ man -k sort
--snip-- 
comm (1)  - compare two sorted files line by line
qsort (3) - sorts an array
sort (1)  - sort lines of text files
sortm (1) - sort messages
tsort (1) - perform topological sort
--snip--

输出结果包括帮助手册的名称、所属的章节以及内容的简要描述。

注解:如果你对本书目前介绍的命令有疑问,可以使用man命令查阅它们的帮助手册。

帮助手册按照命令类型被组织为很多个章节,章节编号出现在章节名后面的括号中,例如ping(8)。表2-3中列出了各章节和它们的编号。

表2-3 在线帮助手册章节列表

章节

简介

1

用户命令

2

系统调用

3

Unix高级编程库文档

4

设备接口和设备驱动程序信息

5

文件描述符(系统配置文件)

6

游戏

7

文件格式、规范和编码(ASCII编码和文件后缀等等)

8

系统命令和服务器

章节1、5、7和8对本书的内容是很好的补充参考。章节4用到的不多,章节6的内容稍微有些单薄。章节3主要是供开发人员参考。在阅读完本书有关系统调用的部分后,你能对章节2的内容有更好的理解。

你可以按序号来选择章节,这会让搜索结果更加精确,因为一旦匹配了搜索关键字,帮助手册会定位到该关键字查找结果的第一页。比如你要搜索有关passwd的信息,可以使用如下命令:

$ man 5 passwd

帮助手册涵盖的是基本内容,你还可以使用--help或者-h选项来获得帮助信息。如ls --help

GNU项目因为不喜欢帮助手册这种方式,引入了info(或者texinfo)。info文档的内容更加丰富,同时也更复杂一些。可以使用info命令查看info文件内容:

$ info command

有一些程序将它们的文档放到目录/usr/share/doc中,而不是maninfo里。你可以在这里搜索需要的文档,当然别忘了还有互联网。

2.14 shell输入输出

至此你已经了解了Unix的基本命令,文件和目录,现在我们可以介绍标准输入输出的重定向了。让我们从标准输出开始。

如果想将命令的执行结果输出到文件(默认是终端屏幕),可以使用重定向字符>

$ command > file

如果文件file不存在,shell会创建一个新文件file。如果file文件已经存在,shell会先清空文件的内容。(一些shell可以通过设置参数来防止文件被清空,如:bash中的set -C命令。)

如果不想把原文件覆盖,你可以使用>>将命令的输出结果加入到文件末尾:

$ command >> file

这个方法在收集多个命令的执行结果时非常有用。

你还可以使用管道字符(|)将一个命令的执行结果输出到另一个命令。例如:

$ head /proc/cpuinfo
$ head /proc/cpuinfo | tr a-z A-Z

你可以使用任意多个管道字符,只需要在每个额外的命令前各加一个管道符即可。

2.14.1 标准错误输出

有的时候你会发现,即使重定向了标准输出,终端屏幕上还是会显示一些信息,其实这是标准错误输出,是用来显示系统错误和调试信息的一种额外的输出流。比如,运行下面的命令后,会发生错误:

$ ls /fffffffff > f

输出完成后,f应该是空的,但你会在终端屏幕上看到以下错误信息,即标准错误输出:

ls: cannot access /fffffffff: No such file or directory

如果有必要,你可以使用2>重定向标准错误输出,例如,使用2>向f发送标准输出,向e发送标准错误输出:

$ ls /fffffffff > f 2> e

这里的2是由shell修改的ID,1是标准输出,2是标准错误输出。

你也可以使用>&将标准输出和标准错误输出重定向到同一个地方,例如,把标准输出和标准错误输出重定向到文件f中,可执行以下命令:

$ ls /fffffffff > f 2>&1

2.14.2 标准输入重定向

使用<操作符将文件内容重定向为命令的标准输入:

$ head < /proc/cpuinfo

你偶尔会遇见要求这种类型的重定向的程序,但因为很多Unix命令可以使用文件名作为参数,所以不太常需要使用<来重定向文件。例如,上述命令也可以写成head /proc/cpuinfo

2.15 理解错误信息

在Linux这样的基于Unix的操作系统中,程序运行出错时你要做的第一件事情必须是查看错误信息,因为大多数情况下,出错的具体原因都能在错误信息里找到。这一点Unix系统做得比其他有些操作系统要好。

2.15.1 解析Unix的错误信息

绝大部分Unix上的应用程序都使用相同的方式处理错误信息,但在任意两个程序的输出结果之间可能会存在些微的差别。例如,你可能会经常遇到这种情况:

$ ls /dsafsda
ls: cannot access /dsafsda: No such file or directory

该信息分为以下三部分。

  • 命令文件名:ls。一些程序不显示命令文件名,这对于脚本调试来说很不方便。但这也不是问题的关键。
  • 文件路径:/dsafsda。这是一条更为具体的信息,而问题就出在这个文件路径上。
  • 错误信息:No such file or directory。这一信息告诉我们错误出在文件路径名上。

将以上的信息综合起来看,你就能得出结论:ls想要访问文件/dsafsda,但是文件不存在。在这个例子里,错误信息很易懂,但是如果你运行的是执行很多命令的脚本,出错信息会变得复杂难懂。

在排错时,务必从第一个错误开始入手。程序报告错误时总是先告诉你它无法完成某一个操作,接下来告诉你一些其他的相关问题。例如我们虚构这样一个场景:

scumd: cannot access /etc/scumd/config: No such file or directory

后面跟着一大串的错误信息,看起来问题很严重。首先不要受它们的影响,专注于第一个错误信息你就知道,要解决的问题只不过是创建一个文件/etc/scumd/config而已。

注解:不要把错误信息和警告信息混为一谈。警告信息看起来像是错误信息,但是它只是告诉我们程序出了问题,但是还能够继续运行。要解决警告信息里面的问题,你可能需要终止当前进程。(有关查看和终止进程的内容,我们将在2.16节介绍。)

2.15.2 常见错误

Unix程序的很多错误与文件和进程有关。下面我们列举一些常见的错误。

No such file or directory

这可能是我们最常遇到的错误:访问一个不存在的文件或目录。由于Unix的I/O系统对文件和目录不做区分,所以当你试图访问一个不存在的文件,进入一个不存在的目录,或将文件写入一个不存在的目录时,都会出现这个错误。

File exists

如果新建文件的名称和现有的文件或者目录重名,就会出现这个错误。

Not a directory, Is a directory

这个错误出现在当你把文件当作目录或者反之,把目录当作文件。例如:

$ touch a
$ touch a/b
touch: a/b: Not a directory

错误出在第二个命令这里,将文件a当作了目录,很多时候你可能需要花点时间来检查文件路径。

No space left on device

说明硬盘空间不足。

Permission denied

当你试图读或写一个没有访问权限的文件或目录时,会遇到这个错误。当你试图执行一个你无权执行(即使你有读的权限)的文件时也会出现这个错误。我们会在2.17节详细介绍。

Operation not permitted

当你试图终止一个你无权终止的进程时,会出现这个错误。

Segmentation fault, Bus error

分段故障,总线错误。分段故障这个错误通常是告诉你,你运行的程序出了问题。可能你的程序试图访问它无权访问的内存空间,这时操作系统就会将其终止。总线错误说明你的程序访问内存的方式有问题。遇到这类错误通常是因为程序的输入数据有问题。

2.16 查看和操纵进程

我们在第1章介绍过,进程就是运行在内存中的程序。每个进程都有一个数字ID,叫进程ID(Process ID,以下简称PID)。可以使用ps命令列出所有正在运行的进程:

$ ps
  PID   TTY  STAT TIME  COMMAND 
  520    p0  S    0:00  -bash 
  545     ?  S    3:59  /usr/X11R6/bin/ctwm -W 
  548     ?  S    0:10  xclock -geometry -0-0 
 2159    pd  SW   0:00  /usr/bin/vi lib/addresses 
31956    p3  R    0:00  ps

每行的字段依次代表以下内容。

  • PID:进程ID。

  • TTY:进程所在的终端设备,稍后详述。

  • STAT:进程状态,就是进程在内存中的状态。例如,S表示进程正在休眠,R表示进程正在运行。(完整的状态列表请参阅帮助手册ps(1)。)

  • TIME:进程目前为止所用CPU时长(格式:mm:ss),就是进程占用CPU的总时长。

  • COMMAND:命令名,请注意进程有可能将其由初始值改为其他。

2.16.1 命令选项

ps命令有很多选项,你可以使用三种方式来设置选项:Unix方式、BSD方式和GNU方式。BSD方式被认为是比较好的一种,因为它相对简单一些。本书也将使用BSD这种方式。下面是一些比较实用的选项组合。

** `ps x` ** 显示当前用户运行的所有进程。
**`ps ax` ** 显示系统当前运行的所有进程,包括其他用户的进程。
** `ps u`** 显示更详细的进程信息。
**`ps w` ** 显示命令的全名,而非仅显示一行以内的内容。

和对其他程序一样,你可以对ps使用选项组合,如ps auxps auxw。你可以将PID作为ps命令的一个参数,用来查看该特定进程的信息,如ps u $$,其中$$是一个shell变量,表示当前的shell进程。(在第8章我们将会介绍toplsof管理员命令,它们能够帮助我们找到进程所在的位置。)

2.16.2 终止进程

要终止一个进程,可以使用kill命令向其发送一个信号,信号是内核发给进程的一条消息。当kill命令运行时,它请求内核发送一个信号给进程。大多数情况下,你可以执行下面的命令:

$ kill pid

信号的种类有很多,默认是TERM(或者terminate)。你可以设置选项来发送不同类型的信号。例如,发送STOP信号可以让进程暂停,而不是终止:

$ kill -STOP pid

被暂停的进程仍然驻留在内存,等待被继续执行。使用CONT信号可以继续执行进程:

$ kill -CONT pid

注解:你可以使用CTRL-C来终止当前运行的进程,效果和kill -INT命令一样。

终止进程最粗鲁的一种方式是使用KILL信号。和其他信号不同,KILL会强行终止进程,并将其移出内存,不会给进程清理和收尾的机会。不到万不得已最好不要使用该信号。

不要随便终止一个你不知道的进程,不然很有可能遇到麻烦。

你还可以使用数字来代替信号名,例如:kill -9等同于kill -KILL。因为内核使用数字来代表不同的信号。如果你知道你想要发送的信号的数字号,可以使用这种方式。

2.16.3 任务控制

Shell也支持任务控制(Job Control),是通过不同的按键和命令向进程发送TSTP(类似STOP)和CONT信号的一种方式。例如,你可以使用CTRL-Z发送TSTP信号来停止进程,然后键入fg(将进程置于前台)或者bg(将进程移入后台,见下一小节)继续运行进程。对初学者来说这些可能不太好理解,不过对于很多高级用户来说它们是很好用的命令。如果使用CTRL-Z而不是CTRL-C,然后置之不理,最终会形成大量处于暂停状态的进程。

提示:你可以使用jobs命令来查看你暂停了哪些进程。

如果你想要运行多个shell,可以单独在每个终端窗口中运行一个程序,将非交互性质的程序置于后台运行(后面将会介绍),或者了解一下screen程序的使用方法。

2.16.4 后台进程

当你在shell上运行命令时,命令行提示符会暂时消失,命令结束时又重新显示。你可以使用&操作符将进程设置为后台运行,这样提示符会一直显示,你在进程运行过程中可以继续其他操作。例如,如果你要解压缩一个很大的文件(我们将在2.18节介绍),同时又不想干等执行结果,你就可以使用下面的命令:

$ gunzip file.gz &

Shell会显示后台新进程的PID,然后直接将命令行提示符显示回来,以便你继续进行其他操作。后台进程在你退出系统后仍会一直运行,这比较适用于那些耗时很长的进程。(你可以设置shell让进程在结束时发送通知。)

后台进程的一个缺点是没法和用户交互(甚至会直接从终端获得输入)。它们可以暂停(用fg恢复运行)或终止以便从标准输入获得数据,也可以将数据输出到标准输出和标准错误,这些数据显示在终端屏幕上,有时会和其他正在运行的进程的输出数据混在一起显示,让人难以辨别。

最好的方式是将输出重定向(输入也可以),比如重定向到文件或别的地方(我们已经在2.14节介绍过),这样屏幕上就不会出现杂乱无章的输出数据。

如果后台进程的输出结果杂乱无章,你需要知道如何整理你的终端窗口内容。bash shell和大多数有全屏交互的程序支持CTRL-L命令,它会清空你的屏幕。进程在从标准输入读取数据之前,经常先使用CTRL-R清空当前行,在错误的时间按了错误的键会让情况更糟。如果不小心在bash提示符下按了CTRL-R,你会被切换到一个让人不知所云的反转搜索模式,这时你可以按ESC退出。

2.17 文件模式和权限

Unix系统中的每一个文件都有一组权限值,用来控制你是否能读、写和运行文件。可以使用命令ls -l来查看这些信息。例如:

-rw-r--r--➊ 1 juser  somegroup    7041 Mar 26 19:34 endnotes.html

➊是文件模式,显示权限及其他附加信息。文件模式由四部分组成,如图2-1。

图像说明文字

图2-1 文件模式信息

本例中第一个字符-是文件类型,-代表常规文件,常规文件是最常见的一种文件类型,另一种常见类型是目录,用d代表。(3.1节中会介绍其余的文件类型。)

本例中的其余部分是文件权限信息,由三部分组成:用户用户组其他。例如,rw-是用户权限,后面的r--是用户组权限,最后的r--是其他权限。

权限信息由四个字符组成:

   
**` r`** 文件可读
** `w` ** 文件可写
**`x`** 文件可执行
**`-` **

用户权限部分(第一组)是针对文件的拥有者,上例中是juser。用户组权限部分是针对somegroup这个用户组中的所有用户。(命令groups可以显示你所在的用户组,详细内容在7.3.5节介绍。)

其他权限部分是针对系统中的所有其他用户,又称为全局权限

注解:权限信息中代表读、写和执行的这三个部分我们称为权限位,如:读位指的是所有三个代表读的部分。

有些可执行文件的执行位是s(setuid)而不是x,表示你将以文件拥有者的身份运行该文件,而不是你自己。很多程序使用s,如passwd命令,因为该命令需要更新/etc/passwd文件,所以必须以文件拥有者(即root用户)的身份运行。

2.17.1 更改文件权限

使用chmod命令更改文件权限。例如,对文件file,要为用户组g和其他用户o加上可读权限r,运行以下命令:

$ chmod g+r file
$ chmod o+r file

也可以使用一行命令:

$ chmod go+r file

如果要取消权限,则使用go-r

注解:不要将全局权限设置为可写,因为这样任何人都能够修改文件。但是这样会让互联网上的人更改你的文件吗?恐怕不能,除非你的系统有网络安全漏洞。果真是这样的话,文件权限也无能为力。

有时你会看到下面这样的命令,使用数字来代表权限:

$ chmod 644 file

这个命令会设置所有的权限位,我们称为绝对权限设置。要知道每一个数字(八进制)代表的权限,可以参考该命令的使用手册。请参考下面的表格。

表2-4 绝对权限模式

模式

详情

用途

644

用户:读/写;用户组,其他:读

文件

600

用户:读/写;用户组,其他:无

文件

755

用户:读/写/执行;用户组,其他:读/执行

目录,程序

700

用户:读/写/执行;用户组,其他:无

目录,程序

711

用户:读/写/执行;用户组,其他:执行

目录

和文件一样,目录也有权限。如果你对目录有读的权限,你就可以列出目录中的内容,但是如果要访问目录中的某个文件,你就必须对目录有可执行的权限(使用绝对值设置权限的时候,目录的可执行权限常常会被不小心取消)。

你还可以使用umask命令来为文件设置预定义的默认权限。例如,如果你想让任何人对文件和目录有读的权限,使用umask 022,反之,如果不想让你的文件和目录可读,使用umask 077(在第13章中我们将详细介绍如何在启动文件中使用umask命令)。

2.17.2 符号链接

符号链接是指向文件或者目录的文件,相当于文件的别名(类似Windows中的快捷方式)。符号链接为复杂的目录提供了便捷快速的访问方式。

在一个长目录列表里,符号链接如下例所示(请注意文件类型是l):

lrwxrwxrwx 1 ruser users 11 Feb 27 13:52 somedir -> /home/origdir

如果你访问somedir,实际访问的是home/origdir目录,符号链接仅仅是指向另一个名字的名字,所以/home/origdir这个目录即使不存在也没有关系。

如果/home/origdir不存在的话,访问somedir的时候系统会报错称somedir不存在。

符号链接不提供其目标路径的详细信息,你只能自己打开这个链接,看看它指向的究竟是文件还是目录。有时候一个符号链接还可以指向另一个符号链接,我们称为链式符号链接

2.17.3 创建符号链接

使用ln -s命令创建符号链接:

$ ln -s target linkname

linkname参数是符号链接名称,target参数是要指向的目标路径,-s选项表示这是一个符号链接(请见稍后的警告部分)。

运行这个命令之前请反复确认,如果你不小心调换了targetlinkname这两个参数的位置,命令变成了:ln -s linkname target,如果linkname这个路径已经存在,一些有趣的事情就会发生。ln会在linkname目录中创建一个名为target的符号链接,如果linkname不是绝对路径,target就会指向它自己。当你使用ln命令遇到问题的时候,请注意检查此类情况。

如果不知道符号链接已经存在的话,就会带来很多麻烦。例如,你有可能无意中会将符号链接文件当作目标文件的副本进行编辑。

警告:创建符号链接的时候,请注意不要忘记-s选项。没有此选项的话,ln命令会创建一个硬链接,为文件创建一个新的名字。新文件拥有老文件的所有状态信息,和符号链接一样,打开这个新文件会直接打开文件内容。除非你掌握了4.5节的内容,否则不要使用符号链接。

符号链接能方便我们管理、组织、共享文件,所以即使有这么多“缺点”,我们还是会用到它。

2.18 归档和压缩文件

了解了文件、权限和相关错误信息之后,让我们来了解一下gziptar

2.18.1 gzip命令

gzip(GNU Zip)命令是Unix上众多标准压缩程序中的一个。GNU Zip生成的压缩文件带有后缀名.gz。解压缩.gz文件使用gunzip file.gz命令,压缩文件使用gzip file命令。

2.18.2 tar命令

gzip命令只压缩单个文件,要压缩和归档多个文件和目录,可以使用tar命令:

$ tar cvf archive.tar file1 file2 ...

tar命令生成的文件带有后缀名.tar,<archive>.tar是生成的归档文件名,file1、file2等是要归档的文件和目录列表。选项c代表创建文件。选项rf的作用则更加具体。

选项v用来显示详细的命令执行信息(比如正在归档的文件和目录名),再加一个v选项可以显示文件大小和权限等信息。如果你不想看到这些信息,可以不用加v选项。

选项f代表文件,后面需要指定一个归档文件名(如<archive>.tar)。如果不指定归档文件名,则归档到磁带设备,如果文件名为-,则是归档到标准输入或者输出。

解压缩tar文件

使用tar命令解压缩.tar文件:

$ tar xvf archive.tar

选项x代表解压模式。你还可以只解压归档文件中的某几个文件,只需要在命令后面加上这些文件的文件名即可。

注解tar命令解压后并不会删除归档文件。

内容预览表模式

在解压一个归档文件之前,通常建议使用选项t来查看归档文件中的内容,t代表内容预览表模式,它会显示归档的文件列表,并且验证归档信息的完整性。如果你不做检查直接解压归档文件,有时会解压出一些很难清理的垃圾内容。

你需要检查压缩包中的文件是否在同一目录下,你可以创建一个临时目录,在其中试着解压一下看看(只要不产生一堆文件,使用mv命令移动一个目录总是容易的)。

解压缩时,你可以使用选项p来保留被归档文件的权限信息。当你使用超级用户运行解压命令时,选项p默认开启。如果你在执行过程中遇到这样那样的问题,请确保你等到tar命令执行完毕并显示提示符。tar命令每次都处理整个归档文件,无论你是解压整个文件或者只是文件中的某部分,所以命令执行过程中请不要中断,因为有些操作是在文件检查之后才开始的,比如权限设置。

2.18.3 压缩归档文件(.tar.gz)

许多初学者对被压缩后的归档文件(后缀为.tar.gz)比较费解。我们可以按照从右到左的顺序来解压和打开此类文件。例如,使用以下命令首先解压缩,然后校验及释放归档文件包:

$ gunzip file.tar.gz
$ tar xvf file.tar

如果需要归档并压缩,则按照相反顺序,先运行tar命令归档,然后运行gzip命令压缩。你可能会逐渐觉得这两个步骤很麻烦,下面我们介绍一些更简便的方法。

2.18.4 zcat命令

上面的命令缺点是执行效率不高,并且会占用很多硬盘空间。管道命令是一个更好的选择,例如:

$ zcat file.tar.gz | tar xvf -

zcat命令等同于gunzip -dc命令。选项d代表解压缩,选项c代表将运行结果输出到标准输出(本例中是输出到tar命令)。

tar命令很常用,它的Linux版本有这样几个选项值得注意:选项z对归档文件自动运行gzip,对创建归档包和释放归档包均适用。例如使用以下命令来验证压缩文件:

$ tar ztvf file.tar.gz

然而,在走捷径以前,最好还是先掌握基本方法。

注解:.tgz文件和.tar.gz文件没有区别,后缀.tgz主要是针对MS-DOS的FAT文件系统。

2.18.5 其他的压缩命令

Unix中的另一个压缩命令是bzip2,生成后缀名为.bz2的文件。该命令执行效率比gzip稍慢,主要用来压缩文本文件,因而在压缩源代码文件的时候比较常用。相应的解压缩命令是bunzip2,可用选项和gzip几乎相同,其中选项j是针对tar命令的压缩和解压缩。

此外xz是另外一个渐受欢迎的压缩命令,对应的解压缩命令是unxz,可用选项和gzip也十分类似。

Linux上的zipunzip与Windows上的.zip文件格式大部分是兼容的,包括.zip和.exe自解压文件。有一个很古老的Unix命令compress支持.Z格式,gunzip命令能够解压缩.Z文件,但是gzip不支持此格式文件的创建。

2.19 Linux目录结构基础

我们前面介绍了文件、目录和帮助手册,现在来看看系统文件。Linux目录结构的详解可以参考文件系统标准结构(FHS, http://www.pathname.com/fhs/)。图2-2为我们展示了Linux的基本目录结构,包括目录/、/usr和/var下的子目录。请注意/usr下的子目录有些和/下的子目录一样。

图像说明文字

图2-2 Linux目录结构

下面这些目录需要重点介绍。

  • /bin目录中存放的是可执行文件,包括大部分基础的Unix命令(如lscp)。该目录中的大部分是由C编译器创建的二进制文件,还有一些现代系统的shell脚本文件。
  • /dev目录中是设备文件,将在第3章详细介绍。
  • /etc目录(读作EHT-see)存放重要的系统配置文件,如用户密码文件、启动文件、设备、网络和其他配置文件。许多都是硬件系统的配置文件。例如,/etc/X11目录中是显示卡和视窗系统的配置文件。
  • /home目录中是用户的个人目录。大多数Unix系统都遵循这个规范。
  • /lib目录中是供可执行程序使用的各种代码库。代码库分为两种:静态库和共享库。/lib目录中一般只有共享库。其他代码库目录,如:/usr/lib中会有静态库和动态库,以及其他的辅助文件(将在第15章详细介绍)。
  • /proc目录中通过一个可浏览的目录与文件接口来存放系统相关信息,比如当前运行的进程和内核的信息。Linux上这个目录的一大部分子目录结构相比其他Unix系统要特别一些,但其他Unix系统大多也有类似的特性。/proc目录中包含了当前正在运行的进程的信息以及一些内核参数。
  • /sys目录类似/proc目录,里面是设备和系统的信息(将在第3章介绍)。
  • /sbin目录中是可执行的系统文件,这些可执行文件用来管理系统。普通用户一般不需要使用,许多命令只能由root用户运行。
  • /tmp目录存放无关紧要的临时文件。所有用户对该目录都有读和写的权限,不过可能对别人的文件没有权限。许多程序会使用这个目录作为保存数据的地方,但如果数据很重要的话请不要存放在/tmp目录中,因为很多系统会在启动时清空/tmp目录,甚至是经常性地清理这个目录里的旧文件。也注意不要让/tmp目录里的垃圾文件占用太多的硬盘空间。
  • /usr目录虽然读作user,但里面并没有用户文件,而是存放着许多Linux系统文件。/usr目录中的很多目录名和root目录上的相同(如/usr/bin和/usr/lib),里面存放的文件类型也相同。(为了让root文件系统占用尽可能少的空间,许多系统文件并没有存放在系统root目录下。)
  • /var目录是程序存放运行时信息的地方,如系统日志、用户信息、缓存和其他信息。(你可能会注意到这里有一个子目录/var/tmp,和/tmp不同的是,系统不会在启动时清空它。)

2.19.1 root目录下的其他目录

root目录下还有以下这些子目录。

  • /boot目录存放内核加载文件。这些文件中存放Linux在第一次启动时的信息,之后的信息并不保存在这里。详见第5章。
  • /media目录是加载可移除设备的地方,比如可移动硬盘。
  • /opt目录一般存放第三方软件,许多系统并没有这个目录。

2.19.2 /usr目录

/usr目录中内容比它的名字多得多,你看一看/usr/bin和/usr/lib的内容就会知道,/usr目录存放那些运行在用户空间中的进程和数据。除了/usr/bin、/usr/sbin1和/usr/lib外,还包括以下内容。

  • /include目录存放C编译器需要使用的头文件。
  • /info目录存放GNU帮助手册(参考2.13节)。
  • /local目录是管理员安装软件的地方,它的结构和/以及/usr类似。
  • /man存放用户手册。
  • /share目录存放Unix系统间的共享文件。过去这个目录通常在网络中被共享,现在使用得越来越少,因为硬盘空间不再是一个大问题,且维护/share目录也让人头疼。/share目录中经常包括/man、/info和其他子目录。

2.19.3 内核位置

Linux系统的内核通常在/vmlinuz或者/boot/vmlinuz中。系统启动时,引导装载程序将这个文件加载到内存并运行(我们将在第5章详细介绍)。

引导装载程序执行完毕后,系统就不再需要内核文件了。不过,系统在运行过程中会根据需要加载和卸载许多模块,我们称之为可加载内核模块,它们在/lib/modules目录下可以找到。

2.20 以超级用户的身份运行命令

继续新内容之前,你需要了解如何以超级用户的身份运行命令。你可能已经知道使用su命令然后输入root用户密码就可以启动root命令行,不过这个方法有以下几个缺点:

  • 对更改系统的命令没有记录信息;
  • 对运行上述命令的用户身份没有记录信息;
  • 无法访问普通Shell环境;
  • 必须输入root密码。

2.20.1 sudo命令

大部分Linux系统中,管理员可以使用自己的用户账号登录,然后使用sudo来以root用户身份执行命令。例如,在第7章中,我们会介绍如何使用vipw命令编辑/etc/passwd文件。例如:

$ sudo vipw

执行sudo命令时,它会使用local2中的系统日志服务将操作写入日志。我们将在第7章详细介绍。

2.20.2 /etc/sudoers

系统当然不会允许任何用户都能够以超级用户的身份运行命令,你需要在/etc/sudoers文件中加入指定的用户。sudo命令有很多选项,使用起来比较复杂。例如,下面的设置允许用户user1和user2不用输入密码即可以超级用户身份运行命令:

User_Alias ADMINS = user1, user2 

ADMINS ALL = NOPASSWD: ALL

root ALL=(ALL) ALL

第一行为user1user2指定一个ADMINS别名,第二行赋予它们权限。ALL = NOPASSWD: ALL表示有ADMINS别名的用户可以运行sudo命令。该行中第二个ALL代表允许执行任何命令,第一个ALL表示允许在任何主机运行命令(如果你有多个主机,你可以针对某个主机或者某一组主机设置,这个我们在这里不详细介绍)。

root ALL=(ALL) ALL表示root用户能够在任何主机上执行任何命令。(ALL)表示root用户可以以任何用户的身份运行命令。你可以通过以下方式将(ALL)权限赋予有ADMINS别名的用户,将(ALL)加入到/etc/sudoers行,如➊所示:

ADMINS ALL = (ALL)➊ NOPASSWD: ALL

注解:可以使用visudo命令编辑/etc/sudoers文件,该命令在保存文件时会做语法检查。

sudo命令我们现在就介绍到这里,详细的使用方法请参考sudoers(5)和sudo(8)帮助手册。(用户切换的详细内容我们将在第7章介绍。)

2.21 前瞻

目前为止你对以下这些命令已经有所了解:运行程序、重定向输出、文件和目录操作、查看进程、查看帮助手册以及用户空间。你应该也学会了以超级用户身份运行命令。关于用户空间组件和内核的详细内容,你可能还不甚了解,但掌握了文件和进程的基础知识后,这些也不再是难事。在下面的章节中,我们就来介绍如何使用这些命令来操作内核和用户空间。

目录

  • 版权声明
  • 前言
  • 致谢
  • 第一版书评
  • 第1章 概述
  • 第2章 基础命令和目录结构
  • 第3章 设备管理
  • 第4章 硬盘和文件系统
  • 第5章 Linux内核的启动
  • 第6章 用户空间的启动
  • 第7章 系统配置:日志、系统时间、批处理任务和用户
  • 第8章 进程与资源利用详解
  • 第9章 网络与配置
  • 第10章 网络应用与服务
  • 第11章 shell脚本
  • 第12章 在网络上传输文件
  • 第13章 用户环境
  • 第14章 Linux桌面概览
  • 第15章 开发工具
  • 第16章 从C代码编译出软件
  • 第17章 在基础上搭建