进程是程序的运行实例(running instance)。运行在计算机中的多个进程都被分配了一个称为进程 ID(PID)的唯一标识数字。同一个程序的多个实例可以同时运行,但是它们各自拥有不同PID和属性。进程属性包括拥有该进程的用户、进程使用的内存数量、进程占用的CPU时间等。这则攻略展示了如何收集进程的相关信息。

10.2.1 预备知识

和进程管理相关的重要命令是toppspgrep。这些命令在所有的Linux发行版中都可以找到。

10.2.2 实战演练

ps可以报告活跃进程的相关信息。这些信息包括:拥有进程的用户、进程的起始时间、进程
对应的命令路径、PID、进程所属的终端(TTY)、进程使用的内存、进程占用的CPU等。例如:

  1. $ ps
  2. PID TTY TIME CMD
  3. 1220 pts/0 00:00:00 bash
  4. 1242 pts/0 00:00:00 ps

ps命令默认只显示从当前终端所启动的进程。第一列是PID,第二列是TTY,第三列是进程的运行时长,最后一列是CMD(进程所对应的命令)。

可以使用命令行参数来修改ps命令的输出。

ps命令默认只显示从当前终端所启动的进程。第一列是PID,第二列是TTY,第三列是进程的运行时长,最后一列是CMD(进程所对应的命令)。

可以使用命令行参数来修改ps命令的输出。

选项-ffull)可以显示多列信息:

  1. $ ps -f
  2. UID PID PPID C STIME TTY TIME CMD
  3. slynux 1220 1219 0 18:18 pts/0 00:00:00 -bash
  4. slynux 1587 1220 0 18:59 pts/0 00:00:00 ps -f
  1. [root@dev workspace]# ps -f
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 9 8 0 19:24 pts/0 00:00:00 -bash
  4. root 25 9 0 19:31 pts/0 00:00:00 ps -f
  5. [root@dev workspace]#

选项-e(every)-ax(all)能够输出系统中运行的所有进程信息。

选项-x(配合-a)可以解除ps默认设置的TTY限制。通常如果使用不带参数的ps命令,只能打印出属于当前终端的进程。

命令ps -eps -efps -ax以及ps -axf都能够生成包含所有进程的报告,提供比ps更多的信息:

  1. $ ps -e | head -5
  2. PID TTY TIME CMD
  3. 1 ? 00:00:00 init
  4. 2 ? 00:00:00 kthreadd
  5. 3 ? 00:00:00 migration/0
  6. 4 ? 00:00:00 ksoftirqd/0
  1. [root@dev workspace]# ps -e | head -5
  2. PID TTY TIME CMD
  3. 1 ? 00:00:00 init
  4. 7 ? 00:00:00 init
  5. 8 ? 00:00:00 init
  6. 9 pts/0 00:00:00 bash
  7. [root@dev workspace]# ps -e | tail -5
  8. 7 ? 00:00:00 init
  9. 8 ? 00:00:00 init
  10. 9 pts/0 00:00:00 bash
  11. 28 pts/0 00:00:00 ps
  12. 29 pts/0 00:00:00 bash
  13. [root@dev workspace]# ps -e | head
  14. PID TTY TIME CMD
  15. 1 ? 00:00:00 init
  16. 7 ? 00:00:00 init
  17. 8 ? 00:00:00 init
  18. 9 pts/0 00:00:00 bash
  19. 30 pts/0 00:00:00 ps
  20. 31 pts/0 00:00:00 head
  21. [root@dev workspace]# ps -ef | head
  22. UID PID PPID C STIME TTY TIME CMD
  23. root 1 0 0 19:24 ? 00:00:00 /init
  24. root 7 1 0 19:24 ? 00:00:00 /init
  25. root 8 7 0 19:24 ? 00:00:00 /init
  26. root 9 8 0 19:24 pts/0 00:00:00 -bash
  27. root 32 9 0 19:46 pts/0 00:00:00 ps -ef
  28. root 33 9 0 19:46 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head
  29. [root@dev workspace]# ps -ax
  30. PID TTY STAT TIME COMMAND
  31. 1 ? Sl 0:00 /init
  32. 7 ? Ss 0:00 /init
  33. 8 ? S 0:00 /init
  34. 9 pts/0 Ss 0:00 -bash
  35. 34 pts/0 R+ 0:00 ps -ax
  36. [root@dev workspace]#

选项-e产生的输出内容很多。我们使用head进行了过滤,只列出了其中的前5项。

选项-o PARAMETER1,PARAMETER2可以指定显示哪些数据。

-o的参数以逗号(,)作为分隔符。逗号与接下来的参数之间是没有空格的。选项-o可以和选项-e配合使用(-oe)来列出系统中运行的所有进程。但如果在-o中需要使用过滤器,例如列出特定用户拥有的进程,那就不能再搭配-e了。因为-e和过滤器结合使用没有任何实际效果,依旧会显示所有的进程。

在下面的例子中,comm代表COMMANDpcpu代表CPU占用率:

  1. $ ps -eo comm,pcpu | head -5
  2. COMMAND %CPU
  3. init 0.0
  4. init 0.0
  5. init 0.0
  6. bash 0.0
  7. ps 0.0
  8. head 0.0

10.2.3 工作原理

选项-o可以使用不同的参数,这些参数及其描述如表10-1所示。

表 10-1

参 数 描 述
pcpu CPU 占用率
pid 进程 ID
ppid 父进程 ID
comm 可执行文件名
cmd 简单命令
user 启动进程的用户
nice 优先级
time 累计的CPU时间
etime 进程启动后运行的时长
tty 所关联的TTY设备
euid 有效用户ID
stat 进程状态
  1. [root@dev workspace]# ps -eo comm,pid,pcpu,ppid,cmd,user,nice,time,etime,tty,euid,stat
  2. COMMAND PID %CPU PPID CMD USER NI TIME ELAPSED TT EUID STAT
  3. init 1 0.0 0 /init root 0 00:00:00 35:18 ? 0 Sl
  4. init 7 0.0 1 /init root 0 00:00:00 35:17 ? 0 Ss
  5. init 8 0.0 7 /init root 0 00:00:00 35:17 ? 0 S
  6. bash 9 0.0 8 -bash root 0 00:00:00 35:17 pts/0 0 Ss
  7. ps 45 0.0 9 ps -eo comm,pid,pcpu,ppid,c root 0 00:00:00 00:00 pts/0

10.2.4 补充内容

ps可以配合grep以及其他工具生成定制的报告。

显示进程的环境变量

有些进程依赖于所定义的环境变量。了解这些环境变量及其取值有助于调试或定制进程。

ps命令通常并不会显示进程的环境信息。输出修饰符e可以将其添加到命令尾部:

  1. $ ps e

简单命令是我们平时使用最频繁的一类命令。它是由空白字符分隔的一系列单词,以shell控制操作符作为结尾。第一个单词指定要执行的命令,余下的单词作为命令参数。shell控制操作符可以是换行符,或者是||&&&;;;||&、()。详情可参阅 Bash Reference Manual,3.2.1节。

请看下面的例子:

  1. $ ps -eo pid,cmd e | tail -n 1
  2. 1238 -bash USER=slynux LOGNAME=slynux HOME=/home/slynux
  3. PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  4. MAIL=/var/mail/slynux SHELL=/bin/bash SSH_CLIENT=10.211.55.2 49277 22
  5. SSH_CONNECTION=10.211.55.2 49277 10.211.55.4 22 SSH_TTY=/dev/pts/0

环境信息可以帮助跟踪apt-get包管理器在使用过程中出现的问题。如果你是通过HTTP代理连接到Internet,你也许需要使用http_proxy=host:port来设置环境变量。如果没有设置的话,apt-get会无法找到代理服务器,进而返回错误信息。只要知道了是没有设置http_proxy,问题就好解决了。

当使用如cron(本章随后会介绍)这类调度工具运行应用程序时,有可能忘了设置所需的环境变量。下面的crontab条目就无法打开基于GUI窗口的应用:

  1. 00 10 * * * /usr/bin/windowapp

因为GUI应用需要使用环境变量DISPLAY。要想确定都需要哪些环境变量,可以先手动运行windowapp,然后使用命令ps -C windowapp -eo cmd e

确定了所需的环境变量之后,将其定义在crontab中的命令之前:

  1. 00 10 * * * DISPLAY=:0 /usr/bin/windowapp

或者

  1. DISPLAY=:0
  2. 00 10 * * * /usr/bin/windowapp

环境变量定义DISPLAY=:0是从ps命令的输出中得到的。

创建进程树状视图

ps命令能够输出进程的PID,但是从子进程一直跟踪到最终的父进程是一件非常枯燥的事。在ps命令的尾部加上f就可以创建进程的树状视图,显示出任务之间的父子关系。下面的例子展示了bash shell所调用的ssh会话,前者运行在xterm中:

  1. $ ps -u root f | grep -A2 xterm | head -3
  2. 15281 ? S 0:00 xterm
  3. 15284 pts/20 Ss+ 0:00 \_ bash
  4. 15286 pts/20 S+ 0:18 \_ ssh 192.168.1.2
  1. [root@dev workspace]# ps -u root f | grep -A2 xterm | head -3
  2. 59 pts/0 S+ 0:00 \_ grep --color=auto -A2 xterm
  3. 60 pts/0 S+ 0:00 \_ /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head -3

对 ps 输出进行排序

ps命令的输出默认是没有经过排序的。选项--sort可以强制ps对输出排序。参数前的+表示升序,-表示降序:

  1. $ ps [OPTIONS] --sort -paramter1,+parameter2,parameter3..

例如,要列出占用CPU最多的前5个进程:

  1. $ ps -eo comm,pcpu --sort -pcpu | head -5
  2. COMMAND %CPU
  3. init 0.0
  4. init 0.0
  5. init 0.0
  6. bash 0.0

输出中显示了依据CPU占用率进行降序排列的前5个进程。

grep可以过滤ps的输出。要想找出当前运行的所有Bash进程,可以使用:

  1. $ ps -eo comm,pid,pcpu,pmem | grep bash
  2. bash 9 0.0 0.0

根据真实用户/ID以及有效用户/ID过滤ps输出

ps命令可以根据指定的真实/有效用户名或ID(real and effective username or ID)对进程进行分组。通过检查每一条输出是否属于参数列表中指定的有效用户或真实用户,ps就能够过滤输出。

  • 使用-u EUSER1,EUSER2 …指定有效用户列表;
  • 使用-U RUSER1,RUSER2 …指定真实用户列表。

例如:

  1. # 显示以 root 作为有效用户 ID 和真实用户 ID 的用户以及 CPU 占用率
  2. $ ps -u root -U root -o user,pcpu
  3. USER %CPU
  4. root 0.0
  5. root 0.0
  6. root 0.0
  7. root 0.0
  8. root 0.0

-o可以和-e结合成-eo的形式,但如果使用了过滤器,就不能再使用-e了,它会使过滤器选项失效。

TTY过滤ps输出

可以通过指定进程所属的TTY来选择ps的输出。选项-t可以指定TTY列表:

  1. $ ps -t TTY1, TTY2 ..

例如:

  1. $ ps -t
  2. PID TTY STAT TIME COMMAND
  3. 9 pts/0 Ss 0:00 -bash
  4. 66 pts/0 R+ 0:00 ps -t

进程线程的相关信息

选项-L可以显示出线程的相关信息。该选项会在输出中添加一列LWP。如果再加上选项-f``(-LF),就会多显示出两列:NLWP(线程数量)和LWP(线程ID

  1. $ ps -Lf
  2. UID PID PPID LWP C NLWP STIME TTY TIME CMD
  3. root 9 8 9 0 1 19:24 pts/0 00:00:00 -bash
  4. root 67 9 67 0 1 20:33 pts/0 00:00:00 ps -Lf

下面的命令可以列出线程数最多的5个进程:

  1. $ ps -eLf --sort -nlwp | head -5
  2. UID PID PPID LWP C NLWP STIME TTY TIME CMD
  3. root 1 0 1 0 3 19:24 ? 00:00:00 /init
  4. root 1 0 5 0 3 19:24 ? 00:00:00 /init
  5. root 1 0 6 0 3 19:24 ? 00:00:00 /init
  6. root 7 1 7 0 1 19:24 ? 00:00:00 /init
  7. $ ps -eLf --sort -nlwp | head
  8. UID PID PPID LWP C NLWP STIME TTY TIME CMD
  9. root 1 0 1 0 3 19:24 ? 00:00:00 /init
  10. root 1 0 5 0 3 19:24 ? 00:00:00 /init
  11. root 1 0 6 0 3 19:24 ? 00:00:00 /init
  12. root 7 1 7 0 1 19:24 ? 00:00:00 /init
  13. root 8 7 8 0 1 19:24 ? 00:00:00 /init
  14. root 9 8 9 0 1 19:24 pts/0 00:00:00 -bash
  15. root 70 9 70 0 1 20:34 pts/0 00:00:00 ps -eLf --sort -nlwp
  16. root 71 9 71 0 1 20:34 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head

指定输出宽度以及所要显示的列

ps命令包含多种可用于选择输出字段的选项。下面表10-2是一些常用的选项。
表 10-2

-f 显示完整格式,包括父进程的起始时间
-u userList 选择userList中的用户所拥有的进程。默认情况下,ps只针对当前用户
-l 长格式列表。显示用户ID、父进程PID、占用内存大小等内容

找出特定命令对应的进程 ID

假设某个命令有多个实例正在运行。在这种情况下,我们需要识别出这些进程的PIDpspgrep命令可以完成这项任务:

  1. $ ps -C COMMAND_NAME

或者

  1. $ ps -C COMMAND_NAME -o pid=

如果在pid后面加上=,这会去掉ps输出中PID一列的列名。要想移除某一列的列名,只需要把=
放在对应参数的后面就行了。

下面的命令可以列出bash进程的PID

  1. $ ps -C bash -o pid=
  2. 9

pgrep命令也可以列出命令的进程ID列表:

  1. $ pgrep bash

pgrep只需要使用命令名的一部分作为参数,例如pgrep ashpgrep bas都没问题。但是ps需要你输入准确的命令名。pgrep也支持输出过滤选项。

如果不使用换行符作为分隔符,那么可以使用选项-d来指定其他的输出分隔符:

  1. $ pgrep COMMAND -d DELIMITER_STRING
  2. $ pgrep bash -d ":"
  3. 1255:1680

选项-u可以过滤用户:

  1. $ pgrep -u root,slynux COMMAND
  1. $ pgrep -u root,slynux bash
  2. 9

其中,rootslynux都是用户名。

选项-c可以返回匹配的进程数量:

  1. $ pgrep -c COMMAND
  2. $ pgrep -c bash
  3. 1

确定系统繁忙程度

系统要么是处于空闲状态,要么是处于过载状态。load average的值描述了系统的负载情况。它指明了系统中可运行进程的平均数量。

uptimetop命令都可以显示平均负载。平均负载由3个值来指定,第1个值指明了1分钟内的平均值,第2个值指明了5分钟内的平均值,第3个值指明了15分钟内的平均值。

uptime命令的输出为:

  1. $ uptime
  2. 20:56:22 up 1:32, 0 users, load average: 0.00, 0.00, 0.00

top 命令

默认情况下,top命令会列出CPU占用最高的进程列表以及基本的系统统计信息,其中包括总的任务数、CPU核心数以及内存占用情况。命令输出每隔几秒钟就会更新一次。

下面的命令显示出了一些系统统计信息以及CPU占用率最高的进程:

  1. $ top
  2. top - 20:58:33 up 1:34, 0 users, load average: 0.00, 0.00, 0.00
  3. Tasks: 5 total, 1 running, 4 sleeping, 0 stopped, 0 zombie
  4. %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
  5. MiB Mem : 7842.4 total, 7491.2 free, 235.8 used, 115.4 buff/cache
  6. MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 7419.9 avail Mem
  7. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  8. 1 root 20 0 1756 1080 1016 S 0.0 0.0 0:00.00 init
  9. 7 root 20 0 1756 80 0 S 0.0 0.0 0:00.00 init
  10. 8 root 20 0 1756 80 0 S 0.0 0.0 0:00.21 init
  11. 9 root 20 0 15108 3824 3152 S 0.0 0.0 0:00.27 bash
  12. 95 root 20 0 52056 4124 3512 R 0.0 0.1 0:00.01 top

10.2.5 参考

10.8 节讲解了如何调度任务。