现代操作系统通常是多任务的,这意味着它们通过快速切换执行程序来创造同时做多件事的假象。Linux内核通过进程来管理这种机制。进程是Linux组织等待CPU轮转的不同程序的方式。 有时候,电脑会变得缓慢或者某个应用程序停止响应。在这一部分中,我们将学习命令行中可用的工具,让我们能够检查程序在做什么,以及如何终止行为异常的进程。

当系统启动时,内核会启动一些自己的活动作为进程,并启动一个叫做init的程序。init反过来运行一系列shell脚本(位于/etc中),这些脚本叫做init脚本,它们启动所有系统服务。
这些服务中的许多都是作为守护进程程序实现的,这些程序只是坐在后台做它们的事情,而没有任何用户界面。所以即使我们没有登录,系统至少也在忙着执行例行的东西。
一个程序可以启动其他程序的事实,在进程方案中表达为父进程产生子进程。
内核维护关于每个进程的信息以帮助保持组织有序。例如,每个进程都被分配一个叫做进程ID或PID的号码。PID按升序分配,init总是获得PID 1。
内核还跟踪分配给每个进程的内存,以及进程恢复执行的准备状态。像文件一样,进程也有所有者和用户ID、有效用户ID等。
重要概念:每个进程都有一个唯一的PID,并且进程之间存在着父子关系。这种关系帮助我们理解系统是如何组织的,以及如何有效地管理进程。
最常用的查看进程的命令(有几个)是ps。ps程序有很多选项,但在最简单的形式中,它这样使用:
|$ ps PID TTY TIME CMD 5198 pts/1 00:00:00 bash 10129 pts/1 00:00:00 ps
这个例子中的结果列出了两个进程,进程5198和进程10129,分别是bash和ps。正如我们所看到的,默认情况下,ps不会显示太多信息,只是显示与当前终端会话相关的进程。
要看到更多信息,我们需要添加一些选项,但在我们这样做之前,让我们看看ps产生的其他字段。
TTY是“Teletype”的缩写,指的是进程的控制终端。Unix在这里显示了它的年龄。TIME字段是进程消耗的CPU时间量。正如我们所看到的,两个进程都没有让计算机工作得很辛苦。
通过添加一个特定的选项,我们能够更全面地了解系统当前的运行状况和进程活动。这就像是给我们提供了一幅更完整的画面,让我们可以看到所有正在进行的进程,而不仅仅是与当前终端相关的那些。
|$ ps x PID TTY STAT TIME COMMAND 2799 ? Ssl 0:00 /usr/libexec/bonobo-activation-server --ac 2820 ? Sl 0:01 /usr/libexec/evolution-data-server-1.10 -- 15647 ? Ss 0:00 /bin/sh /usr/bin/startkde 15751 ? Ss 0:00 /usr/bin/ssh-agent /usr/bin/dbus-launch -- 15754 ? S 0:00 /usr/bin/dbus-launch --exit-with-session
添加“x”选项(注意前面没有破折号)告诉ps显示我们所有的进程,不管它们由什么终端控制。TTY列中“?”的存在表示没有控制终端。使用这个选项,我们看到我们拥有的每个进程的列表。
由于系统运行很多进程,ps产生一个很长的列表。通常将ps的输出通过管道传递给less以便更容易查看是有帮助的。一些选项组合也产生很长的输出行,所以最大化终端模拟器窗口可能也是一个好主意。
我能能够观察到上面的输出中添加了一个名为STAT的新列。STAT是“state”的缩写,揭示了进程的当前状态:
在使用ps命令时,另一个常用且非常有用的选项组合是“aux”(注意,这里不需要在选项前加破折号)。这个选项组合能够为我们提供更为详尽的信息。
通过使用“aux”选项,我们不仅可以看到所有用户的进程,还能获取到每个进程的资源使用情况,比如CPU和内存的占用率。
|$ ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2136 644 ? Ss Mar05 0:31 init root 2 0.0 0.0 0 0 ? S< Mar05 0:00 [kt] root 3 0.0 0.0 0 0
这组选项显示属于每个用户的进程。使用没有前导破折号的选项会调用具有“BSD风格”行为的命令。Linux版本的ps可以模拟在几个不同Unix实现中找到的ps程序的行为。
使用这些选项,我们得到这些额外的列:
虽然ps命令可以揭示很多关于机器在做什么的信息,但它只提供了ps命令执行时刻机器状态的快照。要看到机器活动的更动态视图,我们需要使用top命令:
|$ top
top程序是一个非常有用的工具,它能够实时地显示系统中所有进程的动态信息。默认情况下,top每隔3秒就会刷新一次显示内容,让我们可以看到进程的最新状态。
这个程序的名字“top”来源于它能够展示系统中“最重要”或“最活跃”的进程。通过top,我们可以按进程的活动程度来排序,轻松识别出哪些进程正在消耗最多的系统资源。
这对于系统管理员来说是一个非常重要的功能,因为它可以帮助我们快速定位和解决性能问题。
top显示由两部分组成:显示顶部的系统摘要,后面是按CPU活动排序的进程表:
|top - 14:59:20 up 6:30, 2 users, load average: 0.07, 0.02, 0.00 Tasks: 109 total, 1 running, 106 sleeping, 0 stopped, 2 zombie Cpu(s): 0.7%us, 1.0%sy, 0.0%ni, 98.3%id, 0.0%wa, 0.0%hi, 0.0%si Mem: 319496k total, 314860k used, 4636k free, 19392k buff Swap: 875500k total, 149128k used, 726372k free,
系统摘要中包含了许多有用的信息。让我们逐一详细解释这些内容:
top程序是一个非常灵活的工具,它可以通过多种键盘命令进行操作。我们可以通过按下h键来打开帮助屏幕,这个屏幕详细列出了所有可用的命令和它们的功能,帮助我们更好地理解和使用top。
如果我们想要退出top程序,只需按下q键即可。这两个命令是最常用的,因为它们分别提供了程序的使用指南和退出的快捷方式。

现在我们可以查看和监控进程了,让我们获得一些对它们的控制。对于我们的实验,我们将使用一个叫做xlogo的小程序作为我们的实验对象。
xlogo程序是X Window System(使我们的显示器上的图形运行的底层引擎)提供的示例程序,它只是显示一个包含X标志的可调整大小的窗口。
首先,让我们了解我们的测试对象:
|$ xlogo
输入命令后,一个包含标志的小窗口应该出现在屏幕的某个地方。在某些系统上,xlogo可能会打印警告消息,但可以安全地忽略。
如果你的系统不包含xlogo程序,尝试使用gedit或kwrite代替。
让我们观察当我们再次运行xlogo时会发生什么。首先,输入xlogo命令并验证程序正在运行。接下来,返回到终端窗口并按Ctrl-c。
|$ xlogo $
在终端中,当我们按下Ctrl-c组合键时,这个动作会发送一个中断信号给正在运行的程序。可以把它想象成我们在轻轻地拍打程序的肩膀,礼貌地请求它停止工作。
这个信号通常会导致程序优雅地终止其运行过程。具体来说,当我们按下Ctrl-c后,xlogo窗口会立即关闭,随后我们会看到shell的提示符重新出现在终端中,表示我们可以继续输入新的命令。
需要注意的是,并不是所有的命令行程序都能通过这种方式被中断,但大多数情况下,这种方法是有效的。
假设我们想要在不终止xlogo程序的情况下让shell提示符返回。我们将通过将程序放在后台来做到这一点。把终端想象成有前台(表面上有可见的东西,比如shell提示符)和后台(表面后面有隐藏的东西)。
要启动一个程序,使其立即放在后台,我们在命令后面加上一个“&”字符:
|$ xlogo & [1] 28236 $
输入命令后,xlogo窗口出现,shell提示符返回,但也打印了一些有趣的数字。这个消息是shell功能的一部分,叫做作业控制。
通过这个消息,shell告诉我们我们已经启动了作业号1(“[1]”),它有PID 28236。如果我们运行ps,我们可以看到我们的进程:
|$ ps PID TTY TIME CMD 10603 pts/1 00:00:00 bash 28236 pts/1 00:00:00 xlogo 28239 pts/1 00:00:00 ps
在Linux的shell中,我们有一个非常有用的功能,叫做作业控制。这个功能不仅允许我们在前台和后台之间切换进程,还提供了一种查看从当前终端启动的所有作业的方式。
通过使用jobs命令,我们可以清晰地看到这些作业的列表。这个命令会列出每个作业的状态,比如正在运行还是已停止,以及它们的作业编号和命令名称。
|$ jobs [1]+ Running xlogo &
结果显示我们有一个作业,编号为“1”,它正在运行,命令是xlogo &。
当一个进程被放置在后台运行时,它就像是戴上了耳塞,对来自键盘的输入充耳不闻。这意味着即使我们尝试使用Ctrl-c这样的组合键来中断它,后台进程也不会受到影响。
要让这个“耳塞”失效,并将进程重新带回到前台,我们需要使用一个名为fg的命令。这个命令的作用就像是把后台进程从幕后拉到台前,让它重新开始接收来自键盘的输入。具体操作如下:
|$ jobs [1]+ Running xlogo & $ fg %1 xlogo
fg命令后面跟着百分号和作业号(叫做jobspec)就能做到。如果我们只有一个后台作业,jobspec是可选的。要终止xlogo,按Ctrl-c。
有时候,我们可能会遇到这样的情况:我们希望暂时停止一个正在运行的进程,但并不想完全终止它。这种操作通常是为了将一个正在前台运行的进程转移到后台,以便我们可以继续在终端中执行其他命令。
要实现这一点,我们可以使用一个非常方便的快捷键组合:Ctrl-z。这个组合键的作用就像是按下了一个暂停按钮,让前台进程暂时停下来。
接下来,我们来实际操作一下:在命令提示符下输入xlogo,按下Enter键启动程序,然后再按下Ctrl-z,看看会发生什么:
|$ xlogo [1]+ Stopped xlogo $
停止xlogo后,我们可以通过尝试调整xlogo窗口的大小来验证程序已经停止。我们会看到它看起来完全死了。我们可以使用fg命令将程序恢复到前台,或者使用bg命令将程序移动到后台:
|$ bg %1 [1]+ xlogo & $
就像我们使用fg命令时,如果只有一个作业,jobspec(作业规范)是可以省略的。现在,让我们来聊聊为什么我们会选择从命令行启动图形程序。
首先,有时候你想运行的程序可能并没有出现在窗口管理器的菜单中,比如说xlogo。这就像你想看一本书,但书架上找不到它,于是你决定去书店直接找。
其次,从命令行启动程序还有一个好处,那就是你可以看到一些在图形界面启动时看不到的错误信息。想象一下,你在家里用遥控器开电视,但电视没反应,你不知道是电视坏了还是遥控器没电。 如果你直接按电视上的开关,可能就会看到一个提示告诉你问题出在哪里。同样地,从命令行启动程序时,如果程序启动失败,我们可能会看到一个错误信息,帮助我们找出问题所在。
此外,一些图形程序还提供了许多有趣且实用的命令行选项。这就像你去餐厅点菜,菜单上有很多隐藏的“秘密菜单”,只有你知道怎么点才能享受到特别的美味。
kill命令用于向程序发送信号。它的最常见语法看起来像这样:
|kill [-signal] PID...
如果命令行上没有指定信号,那么默认发送TERM(终止)信号。kill命令最常用于发送以下信号:
让我们试试kill命令:
|$ xlogo & [1] 13546 $ kill -1 13546 [1]+ Hangup xlogo
在这个例子中,我们在后台启动xlogo程序,然后用kill向它发送HUP信号。xlogo程序终止,shell指示后台进程已接收到挂断信号。
在看到消息之前,我们可能需要按几次Enter键。注意信号可以通过数字或名称指定,包括前缀为字母“SIG”的名称:
|$ xlogo & [1] 13601 $ kill -INT 13601 [1]+ Interrupt xlogo $ xlogo & [1] 13608 $ kill -SIGINT 13608 [1]+ Interrupt xlogo
就像我们在计算机中创建的文件有一个明确的所有者一样,进程也有它的“主人”。这个主人通常是启动进程的用户。
想象一下,进程就像是一个小助手,只有它的主人才能命令它做事情,比如终止它的工作。为了使用kill命令向进程发送信号,你必须是这个进程的所有者,或者拥有超级用户的权限。
超级用户就像是系统中的管理员,拥有对所有进程的控制权。因此,只有在你是进程的主人或者拥有超级用户权限时,才能成功地使用kill命令来管理进程。
除了上面最常用于kill的信号列表外,还有其他经常被系统使用的信号。以下是其他常见信号的列表:
对于好奇的人来说,可以用以下命令看到信号的完整列表:
|$ kill -l
我们还可以使用killall命令来向多个进程发送信号。这个命令的强大之处在于,它允许我们通过指定程序名称或用户名来匹配多个进程。
想象一下,如果我们有很多个相同的程序在运行,而我们希望一次性终止它们,killall命令就像是一个魔法棒,可以帮助我们轻松实现这一目标。它的基本语法如下:
|killall [-u user] [-signal] name...
为了演示,我们将启动几个xlogo程序的实例,然后终止它们:
|$ xlogo & [1] 18801 $ xlogo & [2] 18802 $ killall xlogo [1]- Terminated xlogo [2]+ Terminated xlogo
与kill一样,您必须有超级用户权限才能向不属于您的进程发送信号。
由于监控进程是重要的系统管理任务,有很多命令用于此。以下是一些可以尝试的命令:
|# 查看进程树 $ pstree # 查看系统资源使用 $ vmstat 5 # 查看特定用户的进程 $ ps -u username # 查看进程的详细信息 $ ps -ef # 按CPU使用率排序 $ ps aux --sort=-%cpu # 按内存使用率排序 $ ps aux --sort=-%mem
下面是一些常用进程管理模式
|# 查找占用CPU最多的进程 $ ps aux --sort=-%cpu | head -10 # 查找占用内存最多的进程 $ ps aux --sort=-%mem | head -10 # 查找特定进程 $ pgrep process_name # 优雅地终止进程 $ kill -TERM PID # 强制终止进程 $ kill -KILL PID # 暂停和恢复进程 $ kill -STOP PID $
在现代计算机系统中,管理多个进程是很常见的事情。Linux系统为此提供了很多好用的工具。因为Linux是全球使用最广泛的服务器操作系统,所以这点很重要。 与其他一些系统不同,Linux主要依靠命令行工具来管理进程。虽然Linux也有图形界面的工具,但命令行工具因为速度快、占用资源少而更受欢迎。 图形界面的工具看起来可能很炫酷,但它们往往会消耗更多的系统资源,这有点得不偿失。