第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?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编程语言,用到几乎所有这些特殊字符!(请注意这里使用的字符名称是美国英语名称。)
字符 |
名称 |
用途 |
---|---|---|
* |
星号 |
正则表达式,通用字符 |
. |
句点 |
当前目录,文件/主机名的分隔符 |
! |
感叹号 |
逻辑非运算符,命令历史 |
| |
管道 |
命令管道 |
/ |
斜线 |
目录分隔符,搜索命令 |
反斜线 |
常量,宏(非目录) |
|
$ |
美元符号 |
变量符号,行尾 |
' |
单引号 |
字符串常量 |
` |
反引号 |
命令替换 |
" |
双引号 |
半字符串常量 |
^ |
脱字符 |
逻辑非运算符,行头 |
~ |
波浪字符 |
逻辑非运算符,目录快捷方式 |
# |
井号 |
注释,预处理,替换 |
[ ] |
方括号 |
范围 |
{ } |
大括号 |
声明块,范围 |
_ |
下划线 |
空格的简易替代 |
注解:控制键我们通常用^来表示,如^C代表CTRL-C。
2.11 命令行编辑
在使用shell时,你应该能注意到可以使用左右箭头来编辑命令行,并且通过上下箭头来查看之前的命令。这是Linux系统的标准操作。
但使用ctrl键来代替箭头键会更加方便。表2-2中的命令是Unix系统的文本编辑标准命令,掌握了这些,你就可以很方便地在任何Unix系统中编辑文本。
按键 |
操作 |
---|---|
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中列出了各章节和它们的编号。
章节 |
简介 |
---|---|
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中,而不是man
和info
里。你可以在这里搜索需要的文档,当然别忘了还有互联网。
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 aux
和ps auxw
。你可以将PID作为ps
命令的一个参数,用来查看该特定进程的信息,如ps u $$
,其中$$
是一个shell变量,表示当前的shell进程。(在第8章我们将会介绍top
和lsof
管理员命令,它们能够帮助我们找到进程所在的位置。)
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
这个命令会设置所有的权限位,我们称为绝对权限设置。要知道每一个数字(八进制)代表的权限,可以参考该命令的使用手册。请参考下面的表格。
模式 |
详情 |
用途 |
---|---|---|
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
选项表示这是一个符号链接(请见稍后的警告部分)。
运行这个命令之前请反复确认,如果你不小心调换了target
和linkname
这两个参数的位置,命令变成了:ln -s linkname target
,如果linkname
这个路径已经存在,一些有趣的事情就会发生。ln
会在linkname
目录中创建一个名为target
的符号链接,如果linkname
不是绝对路径,target
就会指向它自己。当你使用ln
命令遇到问题的时候,请注意检查此类情况。
如果不知道符号链接已经存在的话,就会带来很多麻烦。例如,你有可能无意中会将符号链接文件当作目标文件的副本进行编辑。
警告:创建符号链接的时候,请注意不要忘记
-s
选项。没有此选项的话,ln
命令会创建一个硬链接,为文件创建一个新的名字。新文件拥有老文件的所有状态信息,和符号链接一样,打开这个新文件会直接打开文件内容。除非你掌握了4.5节的内容,否则不要使用符号链接。
符号链接能方便我们管理、组织、共享文件,所以即使有这么多“缺点”,我们还是会用到它。
2.18 归档和压缩文件
了解了文件、权限和相关错误信息之后,让我们来了解一下gzip
和tar
。
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
代表创建文件。选项r
和f
的作用则更加具体。
选项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上的zip
和unzip
与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命令(如
ls
和cp
)。该目录中的大部分是由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
第一行为user1
和user2
指定一个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 前瞻
目前为止你对以下这些命令已经有所了解:运行程序、重定向输出、文件和目录操作、查看进程、查看帮助手册以及用户空间。你应该也学会了以超级用户身份运行命令。关于用户空间组件和内核的详细内容,你可能还不甚了解,但掌握了文件和进程的基础知识后,这些也不再是难事。在下面的章节中,我们就来介绍如何使用这些命令来操作内核和用户空间。