第 4 章 更多的 bash shell 命令

本章内容

  • 管理进程
  • 获取磁盘统计信息
  • 挂载新磁盘
  • 排序数据
  • 归档数据

第3章介绍了Linux文件系统上切换目录以及处理文件和目录的基本知识。文件管理和目录管理是Linux shell的主要功能之一。不过,在开始脚本编程之前,我们还需要了解一下其他方面的知识。本章将详细介绍Linux系统管理命令,演示如何通过命令行命令来探查Linux 系统的内部信息,最后介绍一些可以用来操作系统上数据文件的命令。

4.1 监测程序

Linux系统管理员面临的最复杂的任务之一就是跟踪运行在系统中的程序——尤其是现在, 图形化桌面集成了大量的应用来生成一个完整的桌面环境。系统中总是运行着大量的程序。
好在有一些命令行工具可以使你的生活轻松一些。本节将会介绍一些能帮你在Linux系统上管理程序的基本工具及其用法。

4.1.1 探查进程

当程序运行在系统上时,我们称之为进程(process)。想监测这些进程,需要熟悉ps命令的用法。ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息。
遗憾的是,随着它的稳健而来的还有复杂性——有数不清的参数,这或许让ps命令成了最难掌握的命令。大多数系统管理员在掌握了能提供他们需要信息的一组参数之后,就一直坚持只使用这组参数。
默认情况下,ps命令并不会提供那么多的信息:

  1. $ ps
  2. PID TTY TIME CMD
  3. 3081 pts/0 00:00:00 bash
  4. 3209 pts/0 00:00:00 ps
  5. $

没什么特别的吧?默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户的进程。在此例中,我们只运行了bash shell(注意,shell也只是运行在系统上的另一个程序而已)以及ps命令本身。
上例中的基本输出显示了程序的进程ID(Process ID,PID)、它们运行在哪个终端(TTY)以及进程已用的CPU时间。

说明 ps命令叫人头疼的地方(也正是它如此复杂的原因)在于它曾经有两个版本。每个版本都有自己的命令行参数集,这些参数控制着输出什么信息以及如何显示。最近,Linux开发人员已经将这两种ps命令格式合并到了单个ps命令中(当然,也加入了他们自己的风格)。

Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:

  • Unix风格的参数,前面加单破折线;
  • BSD风格的参数,前面不加破折线;
  • GNU风格的长参数,前面加双破折线。

下面将进一步解析这3种不同的参数类型,并举例演示它们如何工作。

  1. Unix风格的参数

Unix风格的参数是从贝尔实验室开发的AT&T Unix系统上原有的ps命令继承下来的。这些参数如表4-1所示。
表4-1 Unix风格的ps命令参数

参 数 描 述
-A 显示所有进程
-N 显示与指定参数不符的所有进程
-a 显示除控制进程(session leader①)和无终端进程外的所有进程
-d 显示除控制进程外的所有进程
-e 显示所有进程
-C cmdlist 显示包含在cmdlist列表中的进程
-G grplist 显示组ID在grplist列表中的进程
-U userlist 显示属主的用户ID在userlist列表中的进程
-g grplist 显示会话或组ID在grplist列表中的进程②
-p pidlist 显示PID在pidlist列表中的进程
-s sesslist 显示会话ID在sesslist列表中的进程
-t ttylist 显示终端ID在ttylist列表中的进程
-u userlist 显示有效用户ID在userlist列表中的进程
-F 显示更多额外输出(相对-f参数而言)
-O format 显示默认的输出列以及format列表指定的特定列
-M 显示进程的安全信息
-c 显示进程的额外调度器信息
-f 显示完整格式的输出
-j 显示任务信息
-l 显示长列表
-o format 仅显示由format指定的列
-y 不要显示进程标记(process flag,表明进程状态的标记)
-Z 显示安全标签(security context)①信息
-H 用层级格式来显示进程(树状,用来显示父进程)
-n namelist 定义了WCHAN列显示的值
-w 采用宽输出模式,不限宽度显示
-L 显示进程中的线程
-V 显示ps命令的版本号

上面给出的参数已经很多了,不过还有很多。使用ps命令的关键不在于记住所有可用的参数, 而在于记住最有用的那些参数。大多数Linux系统管理员都有自己的一组参数,他们会牢牢记住这些用来提取有用的进程信息的参数。举个例子,如果你想查看系统上运行的所有进程,可用-ef 参数组合(ps命令允许你像这样把参数组合在一起)。

  1. $ ps -ef
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 1 0 0 11:29 ? 00:00:01 init [5]
  4. root 2 0 0 11:29 ? 00:00:00 [kthreadd]
  5. root 3 2 0 11:29 ? 00:00:00 [migration/0]
  6. root 4 2 0 11:29 ? 00:00:00 [ksoftirqd/0]
  7. root 5 2 0 11:29 ? 00:00:00 [watchdog/0]
  8. root 6 2 0 11:29 ? 00:00:00 [events/0]
  9. root 7 2 0 11:29 ? 00:00:00 [khelper]
  10. root 47 2 0 11:29 ? 00:00:00 [kblockd/0]
  11. root 48 2 0 11:29 ? 00:00:00 [kacpid]
  12. 68 2349 1 0 11:30 ? 00:00:00 hald
  13. root 3078 1981 0 12:00 ? 00:00:00 sshd: rich [priv]
  14. rich 3080 3078 0 12:00 ? 00:00:00 sshd: rich@pts/0
  15. rich 3081 3080 0 12:00 pts/0 00:00:00 -bash
  16. rich 4445 3081 3 13:48 pts/0 00:00:00 ps -ef
  17. $

上例中,我们略去了输出中的不少行,以节约空间。但如你所见,Linux系统上运行着很多进程。这个例子用了两个参数:-e参数指定显示所有运行在系统上的进程;-f参数则扩展了输出,这些扩展的列包含了有用的信息。

  • UID:启动这些进程的用户。
  • PID:进程的进程ID。
  • PPID:父进程的进程号(如果该进程是由另一个进程启动的)。
  • C:进程生命周期中的CPU利用率。
  • STIME:进程启动时的系统时间。4
  • TTY:进程启动时的终端设备。
  • TIME:运行进程需要的累计CPU时间。
  • CMD:启动的程序名称。

上例中输出了合理数量的信息,这也正是大多数系统管理员希望看到的。如果想要获得更多的信息,可采用-l参数,它会产生一个长格式输出。

  1. $ ps -l
  2. F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
  3. 0 S 500 3081 3080 0 80 0 - 1173 wait pts/0 00:00:00 bash
  4. 0 R 500 4463 3081 1 80 0 - 1116 - pts/0 00:00:00 ps
  5. $

注意使用了-l参数之后多出的那些列。

  • F:内核分配给进程的系统标记。
  • S:进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,进程已结束但父进程已不存在;T代表停止)。
  • PRI:进程的优先级(越大的数字代表越低的优先级)。
  • NI:谦让度值用来参与决定优先级。
  • ADDR:进程的内存地址。
  • SZ:假如进程被换出,所需交换空间的大致大小。
  • WCHAN:进程休眠的内核函数的地址。
  1. BSD风格的参数

了解了Unix风格的参数之后,我们来一起看一下BSD风格的参数。伯克利软件发行版(Berkeley software distribution,BSD)是加州大学伯克利分校开发的一个Unix版本。它和AT&T Unix系统有许多细小的不同,这也导致了多年的Unix争论。BSD版的ps命令参数如表4-2所示。
表4-2 BSD风格的ps命令参数

参 数 描 述
T
a 显示跟任意终端关联的所有进程
g 显示所有的进程,包括控制进程
r 仅显示运行中的进程
x 显示所有的进程,甚至包括未分配任何终端的进程
U userlist 显示归userlist列表中某用户ID所有的进程
p pidlist 显示PID在pidlist列表中的进程
t ttylist 显示所关联的终端在ttylist列表中的进程
O format 除了默认输出的列之外,还输出由format指定的列
X 按过去的Linux i386寄存器格式显示
Z 将安全信息添加到输出中
j 显示任务信息
l 采用长模式
o format 仅显示由format指定的列
s 采用信号格式显示
u 采用基于用户的格式显示
v 采用虚拟内存格式显示
N namelist 定义在WCHAN列中使用的值
O order 定义显示信息列的顺序
S 将数值信息从子进程加到父进程上,比如CPU和内存的使用情况
c 显示真实的命令名称(用以启动进程的程序名称)
e 显示命令使用的环境变量
f 用分层格式来显示进程,表明哪些进程启动了哪些进程
h 不显示头信息
k sort 指定用以将输出排序的列
n 和WCHAN信息一起显示出来,用数值来表示用户ID和组ID
w 为较宽屏幕显示宽输出
H 将线程按进程来显示
m 在进程后显示线程
L 列出所有格式指定符
V 显示ps命令的版本号

如你所见,Unix和BSD类型的参数有很多重叠的地方。使用其中某种类型参数得到的信息也同样可以使用另一种获得。大多数情况下,你只要选择自己所喜欢格式的参数类型就行了(比如你在使用Linux之前就已经习惯BSD环境了)。
在使用BSD参数时,ps命令会自动改变输出以模仿BSD格式。下例是使用l参数的输出:

  1. $ ps l
  2. F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
  3. 0 500 3081 3080 20 0 4692 1432 wait Ss pts/0 0:00 -bash
  4. 0 500 5104 3081 20 0 4468 844 - R+ pts/0 0:00 ps l
  5. $

注意,其中大部分的输出列跟使用Unix风格参数时的输出是一样的,只有一小部分不同。

  • VSZ:进程在内存中的大小,以千字节(KB)为单位。
  • RSS:进程在未换出时占用的物理内存。
  • STAT:代表当前进程状态的双字符状态码。

许多系统管理员都喜欢BSD风格的l参数。它能输出更详细的进程状态码(STAT列)。双字符状态码能比Unix风格输出的单字符状态码更清楚地表示进程的当前状态。
第一个字符采用了和Unix风格S列相同的值,表明进程是在休眠、运行还是等待。第二个参数进一步说明进程的状态。

  • <:该进程运行在高优先级上。
  • N:该进程运行在低优先级上。
  • L:该进程有页面锁定在内存中。
  • s:该进程是控制进程。
  • l:该进程是多线程的。
  • +:该进程运行在前台。

从前面的例子可以看出,bash命令处于休眠状态,但同时它也是一个控制进程(在我的会话中,它是主要进程),而ps命令则运行在系统的前台。

  1. GNU长参数

最后,GNU开发人员在这个新改进过的ps命令中加入了另外一些参数。其中一些GNU长参数复制了现有的Unix或BSD类型的参数,而另一些则提供了新功能。表4-3列出了现有的GNU长参数。
表4-3 GNU风格的ps命令参数

参 数 描 述
—deselect 显示所有进程,命令行中列出的进程
—Group grplist 显示组ID在grplist列表中的进程
—User userlist 显示用户ID在userlist列表中的进程
—group grplist 显示有效组ID在grplist列表中的进程
—pid pidlist 显示PID在pidlist列表中的进程
—ppid pidlist 显示父PID在pidlist列表中的进程
—sid sidlist 显示会话ID在sidlist列表中的进程
—tty ttylist 显示终端设备号在ttylist列表中的进程
—user userlist 显示有效用户ID在userlist列表中的进程
—format format 仅显示由format指定的列
—context 显示额外的安全信息
—cols n 将屏幕宽度设置为n列
—columns n 将屏幕宽度设置为n列
—cumulative 包含已停止的子进程的信息
—forest 用层级结构显示出进程和父进程之间的关系
—headers 在每页输出中都显示列的头
—no-headers 不显示列的头
—lines n 将屏幕高度设为n行
—rows n 将屏幕高度设为n排
—sort order 指定将输出按哪列排序
—width n 将屏幕宽度设为n列
—help 显示帮助信息
—info 显示调试信息
—version 显示ps命令的版本号

可以将GNU长参数和Unix或BSD风格的参数混用来定制输出。GNU长参数中一个着实让人喜爱的功能就是—forest参数。它会显示进程的层级信息,并用ASCII字符绘出可爱的图表。

  1. 1981 ? 00:00:00 sshd
  2. 3078 ? 00:00:00 \_ sshd
  3. 3080 ? 00:00:00 \_ sshd
  4. 3081 pts/0 00:00:00 \_ bash
  5. 16676 pts/0 00:00:00 \_ ps

这种格式让跟踪子进程和父进程变得十分容易。

4.1.2 实时监测进程

ps命令虽然在收集运行在系统上的进程信息时非常有用,但也有不足之处:它只能显示 某个特定时间点的信息。如果想观察那些频繁换进换出的内存的进程趋势,用ps命令就不方便了。
而top命令刚好适用这种情况。top命令跟ps命令相似,能够显示进程信息,但它是实时显 示的。图4-1是top命令运行时输出的截图。
输出的第一部分显示的是系统的概况:第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载。
平均负载有3个值:最近1分钟的、最近5分钟的和最近15分钟的平均负载。值越大说明系统的负载越高。由于进程短期的突发性活动,出现最近1分钟的高负载值也很常见,但如果近15分钟内的平均负载都很高,就说明系统可能有问题。

说明 Linux系统管理的要点在于定义究竟到什么程度才算是高负载。这个值取决于系统的硬件配置以及系统上通常运行的程序。对某个系统来说是高负载的值可能对另一系统来说就是正常值。通常,如果系统的负载值超过了2,就说明系统比较繁忙了。

第二行显示了进程概要信息——top命令的输出中将进程叫作任务(task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。

4
第 4 章 更多的 bash shell 命令 - 图1

图4-1 top命令运行时的输出
下一行显示了CPU的概要信息。top根据进程的属主(用户还是系统)和进程的状态(运行、空闲还是等待)将CPU利用率分成几类输出。
紧跟其后的两行说明了系统内存的状态。第一行说的是系统的物理内存:总共有多少内存, 当前用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间(如果分配了的话)的状态而言的。
最后一部分显示了当前运行中的进程的详细列表,有些列跟ps命令的输出类似。

  • PID:进程的ID。
  • USER:进程属主的名字。
  • PR:进程的优先级。
  • NI:进程的谦让度值。
  • VIRT:进程占用的虚拟内存总量。
  • RES:进程占用的物理内存总量。
  • SHR:进程和其他进程共享的内存总量。
  • S:进程的状态(D代表可中断的休眠状态,R代表在运行状态,S代表休眠状态,T代表跟踪状态或停止状态,Z代表僵化状态)。
  • %CPU:进程使用的CPU时间比例。
  • %MEM:进程使用的内存占可用内存的比例。
  • TIME+:自进程启动到目前为止的CPU时间总量。
  • COMMAND:进程所对应的命令行名称,也就是启动的程序名。

默认情况下,top命令在启动时会按照%CPU值对进程排序。可以在top运行时使用多种交互命令重新排序。每个交互式命令都是单字符,在top命令运行时键入可改变top的行为。键入f允许你选择对输出进行排序的字段,键入d允许你修改轮询间隔。键入q可以退出top。用户在top 命令的输出上有很大的控制权。用这个工具就能经常找出占用系统大部分资源的罪魁祸首。当然了,一旦找到,下一步就是结束这些进程。这也正是接下来的话题。

4.1.3 结束进程

作为系统管理员,很重要的一个技能就是知道何时以及如何结束一个进程。有时进程挂起了, 只需要动动手让进程重新运行或结束就行了。但有时,有的进程会耗尽CPU且不释放资源。在这两种情景下,你就需要能控制进程的命令。Linux沿用了Unix进行进程间通信的方法。
在Linux中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完善的程序都能接收和处理标准Unix进程信号。这些信号都列在了表4-4中。
表4-4 Linux进程信号

信 号 名 称 描 述
1 HUP 挂起
2 INT 中断
3 QUIT 结束运行
9 KILL 无条件终止
11 SEGV 段错误
15 TERM 尽可能终止
17 STOP 无条件停止运行,但不终止
18 TSTP 停止或暂停,但继续在后台运行
19 CONT 在STOP或TSTP之后恢复执行

在Linux上有两个命令可以向运行中的进程发出进程信号。

  1. kill命令

kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的全部PID发送一个TERM信号。遗憾的是,你只能用进程的PID而不能用命令名,所以kill命令有时并不好用。
要发送进程信号,你必须是进程的属主或登录为root用户。

  1. $ kill 3940
  2. -bash: kill: (3940) - Operation not permitted
  3. $

TERM信号告诉进程可能的话就停止运行。不过,如果有不服管教的进程,那它通常会忽略这个请求。如果要强制终止,-s参数支持指定其他信号(用信号名或信号值)。你能从下例中看出,kill命令不会有任何输出。

  1. # kill -s HUP 3940 #

要检查kill命令是否有效,可再运行ps或top命令,看看问题进程是否已停止。

  1. killall命令

killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通配符,这在系统因负载过大而变得很慢时很有用。

  1. # killall http* #

4
上例中的命令结束了所有以http开头的进程,比如Apache Web服务器的httpd服务。

警告 以root用户身份登录系统时,使用killall命令要特别小心,因为很容易就会误用通配符而结束了重要的系统进程。这可能会破坏文件系统。

4.2 监测磁盘空间

系统管理员的另一个重要任务就是监测系统磁盘的使用情况。不管运行的是简单的Linux台式机还是大型的Linux服务器,你都要知道还有多少空间可留给你的应用程序。
在Linux系统上有几个命令行命令可以用来帮助管理存储媒体。本节将介绍在日常系统管理中经常用到的核心命令。

4.2.1 挂载存储媒体

如第3章中讨论的,Linux文件系统将所有的磁盘都并入一个虚拟目录下。在使用新的存储媒体之前,需要把它放到虚拟目录下。这项工作称为挂载(mounting)。
在今天的图形化桌面环境里,大多数Linux发行版都能自动挂载特定类型的可移动存储媒体。可移动存储媒体指的是可从PC上轻易移除的媒体,比如CD-ROM、软盘和U盘。
如果用的发行版不支持自动挂载和卸载可移动存储媒体,就必须手动完成。本节将介绍一些可以帮你管理可移动存储设备的Linux命令行命令。

  1. mount命令

Linux上用来挂载媒体的命令叫作mount。默认情况下,mount命令会输出当前系统上挂载的设备列表。

  1. $ mount
  2. /dev/mapper/VolGroup00-LogVol00 on / type ext3 (rw) proc on /proc type proc (rw)
  3. sysfs on /sys type sysfs (rw)
  4. devpts on /dev/pts type devpts (rw,gid=5,mode=620)
  5. /dev/sda1 on /boot type ext3 (rw) tmpfs on /dev/shm type tmpfs (rw)
  6. none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw) sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
  7. /dev/sdb1 on /media/disk type vfat (rw,nosuid,nodev,uhelper=hal,shortname=lower,uid=503)
  8. $

mount命令提供如下四部分信息:

  • 媒体的设备文件名
  • 媒体挂载到虚拟目录的挂载点
  • 文件系统类型
  • 已挂载媒体的访问状态

上面例子的最后一行输出中,U盘被GNOME桌面自动挂载到了挂载点/media/disk。vfat文件系统类型说明它是在Windows机器上被格式化的。
要手动在虚拟目录中挂载设备,需要以root用户身份登录,或是以root用户身份运行sudo命令。下面是手动挂载媒体设备的基本命令:

  1. mount -t type device directory

type参数指定了磁盘被格式化的文件系统类型。Linux可以识别非常多的文件系统类型。如果是和Windows PC共用这些存储设备,通常得使用下列文件系统类型。

  • vfat:Windows长文件系统。
  • ntfs:Windows NT、XP、Vista以及Windows 7中广泛使用的高级文件系统。
  • iso9660:标准CD-ROM文件系统。

大多数U盘和软盘会被格式化成vfat文件系统。而数据CD则必须使用iso9660文件系统类型。后面两个参数定义了该存储设备的设备文件的位置以及挂载点在虚拟目录中的位置。比如说,手动将U盘/dev/sdb1挂载到/media/disk,可用下面的命令:

  1. mount -t vfat /dev/sdb1 /media/disk

媒体设备挂载到了虚拟目录后,root用户就有了对该设备的所有访问权限,而其他用户的访问则会被限制。你可以通过目录权限(将在第7章中介绍)指定用户对设备的访问权限。
如果要用到mount命令的一些高级功能,表4-5中列出了可用的参数。
表4-5 mount命令的参数

参 数 描 述
-a 挂载/etc/fstab文件中指定的所有文件系统
-f 使mount命令模拟挂载设备,但并不真的挂载
-F 和-a参数一起使用时,会同时挂载所有文件系统
-v 详细模式,将会说明挂载设备的每一步
-I 不启用任何/sbin/mount.filesystem下的文件系统帮助文件
-l 给ext2、ext3或XFS文件系统自动添加文件系统标签
-n 挂载设备,但不注册到/etc/mtab已挂载设备文件中
-p num 进行加密挂载时,从文件描述符num中获得密码短语
-s 忽略该文件系统不支持的挂载选项
-r 将设备挂载为只读的
-w 将设备挂载为可读写的(默认参数)
-L label 将设备按指定的label挂载
-U uuid 将设备按指定的uuid挂载
-O 和-a参数一起使用,限制命令只作用到特定的一组文件系统上
-o 给文件系统添加特定的选项

-o参数允许在挂载文件系统时添加一些以逗号分隔的额外选项。以下为常用的选项。

  • ro:以只读形式挂载。
  • rw:以读写形式挂载。
  • user:允许普通用户挂载文件系统。
  • check=none:挂载文件系统时不进行完整性校验。
  • loop:挂载一个文件。
  1. umount命令

从Linux系统上移除一个可移动设备时,不能直接从系统上移除,而应该先卸载。

窍门 Linux上不能直接弹出已挂载的CD。如果你在从光驱中移除CD时遇到麻烦,通常是因为该CD还挂载在虚拟目录里。先卸载它,然后再去尝试弹出。

卸载设备的命令是umount(是的,你没看错,命令名中并没有字母n,这一点有时候很让人困惑)。umount命令的格式非常简单:

  1. umount [directory | device ]

umount命令支持通过设备文件或者是挂载点来指定要卸载的设备。如果有任何程序正在使用设备上的文件,系统就不会允许你卸载它:

  1. [root@testbox mnt]# umount /home/rich/mnt
  2. umount: /home/rich/mnt: device is busy
  3. umount: /home/rich/mnt: device is busy
  4. [root@testbox mnt]# cd /home/rich
  5. [root@testbox rich]# umount /home/rich/mnt
  6. [root@testbox rich]# ls -l mnt
  7. total 0 [root@testbox rich]#

上例中,命令行提示符仍然在挂载设备的文件系统目录中,所以umount命令无法卸载该镜像文件。一旦命令提示符移出该镜像文件的文件系统,umount命令就能卸载该镜像文件。①

4.2.2使用 df 命令

有时你需要知道在某个设备上还有多少磁盘空间。df命令可以让你很方便地查看所有已挂载磁盘的使用情况。

  1. $ df
  2. Filesystem 1K-blocks Used Available Use% Mounted on
  3. /dev/sda2 18251068 7703964 9605024 45% /
  4. /dev/sda1 101086 18680 77187 20% /boot
  5. tmpfs 119536 0 119536 0% /dev/shm
  6. /dev/sdb1 127462 113892 13570 90% /media/disk
  7. $

df命令会显示每个有数据的已挂载文件系统。如你在前例中看到的,有些已挂载设备仅限系统内部使用。命令输出如下:

  • 设备的设备文件位置;
  • 能容纳多少个1024字节大小的块;
  • 已用了多少个1024字节大小的块;
  • 还有多少个1024字节大小的块可用;
  • 已用空间所占的比例;
  • 设备挂载到了哪个挂载点上。

df命令有一些命令行参数可用,但基本上不会用到。一个常用的参数是-h。它会把输出中的磁盘空间按照用户易读的形式显示,通常用M来替代兆字节,用G替代吉字节。

  1. $ df -h
  2. Filesystem Size Used Avail Use% Mounted on
  3. /dev/sdb2 18G 7.4G 9.2G 45% /
  4. /dev/sda1 99M 19M 76M 20% /boot
  5. tmpfs 117M 0 117M 0% /dev/shm
  6. /dev/sdb1 125M 112M 14M 90% /media/disk
  7. $

说明 Linux系统后台一直有进程来处理文件或使用文件。df命令的输出值显示的是Linux系统认为的当前值。有可能系统上有运行的进程已经创建或删除了某个文件,但尚未释放文件。这个值是不会算进闲置空间的。

4.2.3 使用 du 命令

通过df命令很容易发现哪个磁盘的存储空间快没了。系统管理员面临的下一个问题是,发生这种情况时要怎么办。
另一个有用的命令是du命令。du命令可以显示某个特定目录(默认情况下是当前目录)的磁盘使用情况。这一方法可用来快速判断系统上某个目录下是不是有超大文件。
默认情况下,du命令会显示当前目录下所有的文件、目录和子目录的磁盘使用情况,它会以磁盘块为单位来表明每个文件或目录占用了多大存储空间。对标准大小的目录来说,这个输出会是一个比较长的列表。下面是du命令的部分输出:w2312341223
`````

  1. $ du
  2. 484 ./.gstreamer-0.10
  3. 8 ./Templates
  4. 8 ./Download
  5. 8 ./.ccache/7/0
  6. 24 ./.ccache/7
  7. 368 ./.ccache/a/d
  8. 384 ./.ccache/a
  9. 424 ./.ccache
  10. 8 ./Public
  11. 8 ./.gphpedit/plugins
  12. 32 ./.gphpedit
  13. 72 ./.gconfd
  14. 128 ./.nautilus/metafiles
  15. 384 ./.nautilus
  16. 72 ./.bittorrent/data/metainfo
  17. 20 ./.bittorrent/data/resume
  18. 144 ./.bittorrent/data
  19. 152 ./.bittorrent
  20. 8 ./Videos
  21. 8 ./Music
  22. 16 ./.config/gtk-2.0
  23. 40 ./.config
  24. 8 ./Documents

每行输出左边的数值是每个文件或目录占用的磁盘块数。注意,这个列表是从目录层级的最底部开始,然后按文件、子目录、目录逐级向上。
这么用du命令(不加参数,用默认参数)作用并不大。我们更想知道每个文件和目录占用了多大的磁盘空间,但如果还得逐页查找的话就没什么意义了。
下面是能让du命令用起来更方便的几个命令行参数。

  • -c:显示所有已列出文件总的大小。
  • -h:按用户易读的格式输出大小,即用K替代千字节,用M替代兆字节,用G替代吉字 节。
  • -s:显示每个输出参数的总计。

系统管理员接下来就是要使用一些文件处理命令操作大批量的数据。这正是下一节的主题。

4.3 处理数据文件

当你有大量数据时,通常很难处理这些信息及提取有用信息。正如在上节中学习的du命令, 系统命令很容易输出过量的信息。
Linux系统提供了一些命令行工具来处理大量数据。本节将会介绍一些每个系统管理员以及日常Linux用户都应该知道的基本命令,这些命令能够让生活变得更加轻松。

4.3.1 排序数据

处理大量数据时的一个常用命令是sort命令。顾名思义,sort命令是对数据进行排序的。默认情况下,sort命令按照会话指定的默认语言的排序规则对文本文件中的数据行排序。

$ cat file1
one
two
three
four
five
$ sort file1
five
four
one
three
two
$

这相当简单。但事情并非总像看起来那样容易。看下面的例子。

$ cat file2
1
2
100
45
3
10
145
75
$ sort file2
1
10
100
145
2
3
45
75
$

如果你本期望这些数字能按值排序,就要失望了。默认情况下,sort命令会把数字当做字符来执行标准的字符排序,产生的输出可能根本就不是你要的。解决这个问题可用-n参数,它会告诉sort命令把数字识别成数字而不是字符,并且按值排序。

$ sort  -n  file2 1
2
3
10
45
75
100
145
$

4
现在好多了!另一个常用的参数是-M,按月排序。Linux的日志文件经常会在每行的起始位置有一个时间戳,用来表明事件是什么时候发生的。

Sep 13 07:10:09 testbox smartd[2718]: Device: /dev/sda, opened

如果将含有时间戳日期的文件按默认的排序方法来排序,会得到类似于下面的结果。

$ sort file3 Apr
Aug Dec Feb Jan Jul Jun Mar May Nov Oct Sep
$

这并不是想要的结果。如果用-M参数,sort命令就能识别三字符的月份名,并相应地排序。

$ sort -M file3 Jan
Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
$

还有其他一些方便的sort参数可用,如表4-6所示。

表4-6 sort命令参数

单破折线 双破折线 描述
-b —ignore-leading-blanks 排序时忽略起始的空白
-C —check=quiet 不排序,如果数据无序也不要报告
-c —check 不排序,但检查输入数据是不是已排序;未排序的话,报告
-d —dictionary-order 仅考虑空白和字母,不考虑特殊字符
-f —ignore-case 默认情况下,会将大写字母排在前面;这个参数会忽略大小写
-g —general-number-sort 按通用数值来排序(跟-n不同,把值当浮点数来排序,支持科学计数法表示的值)
-i —ignore-nonprinting 在排序时忽略不可打印字符
-k —key=POS1[,POS2] 排序从POS1位置开始;如果指定了POS2的话,到POS2位置结束
-M —month-sort 用三字符月份名按月份排序
-m —merge 将两个已排序数据文件合并
-n —numeric-sort 按字符串数值来排序(并不转换为浮点数)
-o —output=file 将排序结果写出到指定的文件中
-R —random-sort 按随机生成的散列表的键值排序
—random-source=FILE 指定-R参数用到的随机字节的源文件
-r —reverse 反序排序(升序变成降序)
-S —buffer-size=SIZE 指定使用的内存大小
-s —stable 禁用最后重排序比较
-T —temporary-directory=DIR 指定一个位置来存储临时工作文件
-t —field-separator=SEP 指定一个用来区分键位置的字符
-u —unique 和-c参数一起使用时,检查严格排序;不和-c参数一起用时,仅输出第一例相似的两行
-z —zero-terminated 用NULL字符作为行尾,而不是用换行符

-k和-t参数在对按字段分隔的数据进行排序时非常有用,例如/etc/passwd文件。可以用-t参数来指定字段分隔符,然后用-k参数来指定排序的字段。举个例子,要对前面提到的密码文件
/etc/passwd根据用户ID进行数值排序,可以这么做:

$ sort -t ':' -k 3 -n /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/etc/news:
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

现在数据已经按第三个字段——用户ID的数值排序。
-n参数在排序数值时非常有用,比如du命令的输出。

$ du -sh  *  | sort  -nr 
1008k    mrtg-2.9.29.tar.gz 972k    bldg1
888k    fbs2.pdf
760k    Printtest
680k    rsync-2.6.6.tar.gz 660k    code
516k    fig1001.tiff 496k    test
496k    php-common-4.0.4pl1-6mdk.i586.rpm 448k    MesaGLUT-6.5.1.tar.gz
400k    plp

注意,-r参数将结果按降序输出,这样就更容易看到目录下的哪些文件占用空间最多。

说明 本例中用到的管道命令(|)将du命令的输出重定向到sort命令。我们将在第11章中进一步讨论。

4.3.2 搜索数据

你会经常需要在大文件中找一行数据,而这行数据又埋藏在文件的中间。这时并不需要手动翻看整个文件,用grep命令来帮助查找就行了。grep命令的命令行格式如下。

grep [options] pattern [file]

grep命令会在输入或指定的文件中查找包含匹配指定模式的字符的行。grep的输出就是包含了匹配模式的行。
下面两个简单的例子演示了使用grep命令来对4.3.1节中用到的文件file1进行搜索。

$ grep three file1
three
$ grep t file1
two
three
$

第一个例子在文件file1中搜索能匹配模式three的文本。grep命令输出了匹配了该模式的行。第二个例子在文件file1中搜索能匹配模式t的文本。这个例子里,file1中有两行匹配了指定的模式,两行都输出了。
由于grep命令非常流行,它经历了大量的更新。有很多功能被加进了grep命令。如果查看一下它的手册页面,你会发现它是多么的无所不能。
如果要进行反向搜索(输出不匹配该模式的行),可加-v参数。

$ grep -v t file1
one
four
five
$

如果要显示匹配模式的行所在的行号,可加-n参数。

$ grep -n t file1
2:two
3:three
$

如果只要知道有多少行含有匹配的模式,可用-c参数。

$ grep -c t file1
2
$

如果要指定多个匹配模式,可用-e参数来指定每个模式。

$ grep -e t -e f file1
two
three
four
five
$

这个例子输出了含有字符t或字符f的所有行。
默认情况下,grep命令用基本的Unix风格正则表达式来匹配模式。Unix风格正则表达式采用特殊字符来定义怎样查找匹配的模式。
要想进一步了解正则表达式的细节,可以参考第20章的内容。以下是在grep搜索中使用正则表达式的简单例子。

$ grep [tf] file1
two
three
four
five
$

正则表达式中的方括号表明grep应该搜索包含t或者f字符的匹配。如果不用正则表达式,grep就会搜索匹配字符串tf的文本。
egrep命令是grep的一个衍生,支持POSIX扩展正则表达式。POSIX扩展正则表达式含有更多的可以用来指定匹配模式的字符(参见第20章)。fgrep则是另外一个版本,支持将匹配模式指定为用换行符分隔的一列固定长度的字符串。这样就可以把这列字符串放到一个文件中,然后在fgrep命令中用其在一个大型文件中搜索字符串了。

4.3.3 压缩数据

如果你接触过Microsoft Windows,就必然用过zip文件。它如此流行,以至于微软从Windows XP开始,就已经将其集成进了自家的操作系统中。zip工具可以将大型文件(文本文件和可执行文件)压缩成占用更少空间的小文件。
Linux包含了多种文件压缩工具。虽然听上去不错,但这实际上经常会在用户下载文件时造成混淆。表4-7列出了Linux上的文件压缩工具。
表4-7 Linux文件压缩工具
4

工 具 文件扩展名 描 述
bzip2 .bz2 采用Burrows-Wheeler块排序文本压缩算法和霍夫曼编码
compress .Z 最初的Unix文件压缩工具,已经快没人用了
gzip .gz GNU压缩工具,用Lempel-Ziv编码
zip .zip Windows上PKZIP工具的Unix实现

compress文件压缩工具已经很少在Linux系统上看到了。如果下载了带.Z扩展名的文件,通常可以用第9 章中介绍的软件包安装方法来安装compress 包(在很多Linux 发行版上叫作ncompress),然后再用uncompress命令来解压文件。gzip是Linux上最流行的压缩工具。
gzip软件包是GNU项目的产物,意在编写一个能够替代原先Unix中compress工具的免费版 本。这个软件包含有下面的工具。

  • gzip:用来压缩文件。
  • gzcat:用来查看压缩过的文本文件的内容。
  • gunzip:用来解压文件。

这些工具基本上跟bzip2工具的用法一样。

$ gzip myprog
$ ls -l my*
-rwxrwxr-x 1 rich rich 2197 2007-09-13 11:29 myprog.gz
$

gzip命令会压缩你在命令行指定的文件。也可以在命令行指定多个文件名甚至用通配符来一次性批量压缩文件。

$ gzip my*
$ ls -l my*
-rwxr--r-- 1 rich rich 103 Sep 6 13:43 myprog.c.gz
-rwxr-xr-x 1 rich rich 5178 Sep 6 13:43 myprog.gz
-rwxr--r-- 1 rich rich 59 Sep 6 13:46 myscript.gz
-rwxr--r-- 1 rich rich 60 Sep 6 13:44 myscript2.gz
$

gzip命令会压缩该目录中匹配通配符的每个文件。

4.3.4 归档数据

虽然zip命令能够很好地将数据压缩和归档进单个文件,但它不是Unix和Linux中的标准归档工具。目前,Unix和Linux上最广泛使用的归档工具是tar命令。
tar命令最开始是用来将文件写到磁带设备上归档的,然而它也能把输出写到文件里,这种用法在Linux上已经普遍用来归档数据了。
下面是tar命令的格式:

tar function [options] object1 object2 ...

function参数定义了tar命令应该做什么,如表4-8所示。
表4-8 tar命令的功能

功 能 长 名 称 描 述
-A —concatenate 将一个已有tar归档文件追加到另一个已有tar归档文件
-c —create 创建一个新的tar归档文件
-d —diff 检查归档文件和文件系统的不同之处
—delete 从已有tar归档文件中删除
-r —append 追加文件到已有tar归档文件末尾
-t —list 列出已有tar归档文件的内容
-u —update 将比tar归档文件中已有的同名文件新的文件追加到该tar归档文件中
-x —extract 从已有tar归档文件中提取文件

每个功能可用选项来针对tar归档文件定义一个特定行为。表4-9列出了这些选项中能和tar 命令一起使用的常见选项。
表4-9 tar命令选项

选 项 描 述
-C dir 切换到指定目录
-f file 输出结果到文件或设备file
-j 将输出重定向给bzip2命令来压缩内容
-p 保留所有文件权限
-v 在处理文件时显示文件
-z 将输出重定向给gzip命令来压缩内容

这些选项经常合并到一起使用。首先,你可以用下列命令来创建一个归档文件:

tar -cvf test.tar test/ test2/

上面的命令创建了名为test.tar的归档文件,含有test和test2目录内容。接着,用下列命令:

tar -tf test.tar

列出tar文件test.tar的内容(但并不提取文件)。最后,用命令:

tar -xvf test.tar

通过这一命令从tar文件test.tar中提取内容。如果tar文件是从一个目录结构创建的,那整个目录结构都会在当前目录下重新创建。
如你所见,tar命令是给整个目录结构创建归档文件的简便方法。这是Linux中分发开源程序源码文件所采用的普遍方法。

窍门 下载了开源软件之后,你会经常看到文件名以.tgz结尾。这些是gzip压缩过的tar文件可以用命令tar -zxvf filename.tgz来解压。

4.4 小结

本章讨论了Linux系统管理员和程序员用到的一些高级bash命令。ps和top命令在判断系统的状态时特别重要,能看到哪些应用在运行以及它们消耗了多少资源。
在可移动存储普及的今天,系统管理员常谈到的另一个话题就是挂载存储设备。mount命令可以将一个物理存储设备挂载到Linux虚拟目录结构上。umount命令用来移除设备。
最后,本章讨论了各种处理数据的工具。sort工具能轻松地对大数据文件进行排序,便于组织数据;grep实用工具能快速检索大数据文件来查找特定信息。Linux上有一些不同的文件压缩工具,包括bzip2、gzip和zip。每种工具都能够压缩大型文件来节省文件系统空间。tar工 具能将整个目录都归档到单个文件中,方便把数据迁移到另外一个系统上。
下一章将讨论各种Linux shell及其使用。Linux允许你在多个shell之间进行通信,这一点在脚本中创建子shell时非常有用。