图源:
什么是进程
进程与程序
.js
文件,或者干脆是直接写在.html
页面中。而C
或者C++
编写的程序则需要在目标机器上编译为机器码(.exe)后才能执行。Java
则一般是打包为jar
包后进行使用。从易用性角度上来说,我比较喜欢Python
,不仅跨平台,而且还有一个方便的包管理软件pip
,直接可以下载和更新Pyhon应用。
而进程则是操作系统在从硬盘读取程序的可执行文件后,为程序在内存中申请相应的资源,并让CPU开始执行可执行文件中的指令后的产物。可以看作是"活的程序"。
程序本身是死的,并不会对用户的输入做出响应,也不会产生有价值的输出,只有被操作系统运行,并成为内存中的一个进程才能发挥相应的作用。
进程与程序的关系可以用下图表示:
图源:
相应的,一个程序可以产生若干个进程。
子进程与父进程
在Linux中,进程之间都是有着父子关系的,比如如果A进程启动了B进程,则A就是B的父进程,而B则是A的子进程。并且子进程会继承父进程的环境变量。
在Linu中,对每一个系统中正在运行的进程,都会给予一个进程编号PID,而为了方便管理,系统也会在子进程的相关信息中记录其父进程的PID,命名为PPID(Parent PID)。
子进程和父进程的关系可以用下图表示:
图源:
我们可以使用ps -l
命令查看当前终端相关的进程:
[icexmoon@xyz ~]$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 1970 1969 0 80 0 - 29252 do_wai pts/0 00:00:00 bash
0 R 1000 2292 1970 0 80 0 - 38331 - pts/0 00:00:00 ps
可以看到ps
这个命令产生的进程PID是2292
,其父进程的PID是1970
,也就是上边的bash
命令产生的进程。所以前者是后者的子进程。
fork and exec
在Linux中,我们往往需要在当前的终端所运行的Bash
进程上启动其它程序,事实上就是通过Bash
来启动子进程,这种启动子进程的流程被称作fork and exec
。
之所以这么说,是因为具体的流程是这样的:
-
对当前进程进行复制(fork),产生一个新的临时进程
-
使用新的临时进程运行程序(exec)
这其中的要点在于,新的临时进程与被fork
的进程除了PID不同以外,其余内容,包括临时变量与环境变量都相同。但同时因为新启动的进程是一个独立的进程(虽然是前者的子进程),所以所有的变量或其它部分的操作都不会影响到原有进程。
常驻内存的进程
为了让系统正常运行,需要一些相关的进程常驻内存(比如之前提过的crond
与atd
等),这类进程被我们称为服务(daemon),为了更好地区别服务和普通进程,服务一般会以d
字母结尾,比如crond
、httpd
等。
daemon也被称为守护进程,因为往往这些进程都可以自启动,如果出现异常中止或被用户手动结束,系统可以通过其它方式重新启动。
Linux的多人多任务环境
Bash环境的任务管理
在前边介绍父进程和子进程的时候,那个图示案例是最简单的那类:开启子进程后父进程挂起,直到子进程结束。事实上子进程和父进程是可以同时处于活动状态的,比如:
[icexmoon@xyz ~]$ cp file1 file2 &
通过在命令结尾添加一个&
符号,可以让命令变成一个任务(job),然后在后台运行。其实就是让运行这个命令的子进程运行的同时父进程(Bash)依然正常运行,以接受用户输入并做出响应。
关于任务管理(job control)相关内容会在后边介绍。
任务管理
任务管理(job control)是当我们登录系统,并获取Bash Shell
后,在单一终端下执行多个任务的操作管理。
什么是任务管理
需要明确的是,这里所说的任务(job),都是在一个终端下通过命令以及&
符号创建的同一个Bash
进程的子进程,我们不能跨越多个终端进行“任务管理”。
在涉及任务管理的时候,有两个概念需要知道:
-
前台
:有命令提示符的环境被称作前台。实质上就是登录后获取的Bash进程,或者直接将Bash挂起后运行的进程。因为这些情况我们都可以直接通过键盘输入和干预,也可以直观看到输出,所以被称为前台。 -
后台
:通过给命令结尾添加&
或者其它方式,将命令在不影响前台Bash进程响应的同时运行或暂停,这种情况下可以认为该命令所处的环境是有别于前台的“后台”。此时我们无法直接通过键盘输入进行干预,需要用到任务管理相关的命令。
任务管理
让命令直接在后台执行
如我们之前所说,如果要让命令在后台执行,最简单的方式就是在结尾加一个&
符号:
[root@xyz ~]# tar -zpcf /tmp/etc.tar.gz /etc &
[1] 2871
[root@xyz ~]# tar: 从成员名中删除开头的“/”
[root@xyz ~]# ll -h /tmp/etc.tar.gz
-rw-r--r--. 1 root root 12M 8月 27 15:10 /tmp/etc.tar.gz
[root@xyz ~]# tar -ztf /tmp/etc.tar.gz
etc/
etc/fstab
etc/crypttab
etc/mtab
etc/resolv.conf
etc/fonts/
etc/fonts/conf.d/
... 省略 ...
需要注意的是,虽然此时tar
命令是在后台执行,不会影响到我们对前台的操作,但是其正常和错误输出依然是显示在前台的,可能会影响到我们前台的信息查看。所以对于在后台执行的命令,我们往往需要结合重定向操作符使用,比如:
[root@xyz ~]# tar -zpcvf /tmp/etc2.tar.gz /etc > /tmp/etc2.log 2>&1 &
[1] 2867
这样我们就可以通过文件查看输出结果或错误信息了:
[root@xyz ~]# less /tmp/etc2.log
此外,当我们创建一个后台任务后,会出现一个输出[1] 2867
,其中[]
中的是任务编号,而后边的数字则是PID,在这个例子中,放到后台的tar
命令对应的任务编号是1,所属进程的PID则是2867
。
最后再强调一下,正如之前所说,任务管理部分的功能仅是针对于当前终端,也就是说产生的任务编号同样仅是对当前终端有效,你是不能在另一个终端中使用当前终端产生的任务编号去操作任务的。
将当前任务暂停后丢入后台
在前台执行任务时按下Ctrl+z
可以将任务暂停,并丢到后台:
[root@xyz ~]# vim ~/.bashrc
[1]+ 已停止 vim ~/.bashrc
[root@xyz ~]# find / -print
... 省略 ...
/proc/746/task/784/fd/1
/proc/746/task/784/fd/2
/proc/746/task/784/fd/3^Z
[2]+ 已停止 find / -print
那个+
表示是最近操作的任务,已停止
是表示任务当前处于暂停状态。
查看后台任务状态
使用jobs
命令可以查看后台的任务状态:
[root@xyz ~]# jobs -l
[1]- 3019 停止 vim ~/.bashrc
[2]+ 3020 停止 find / -print
-l
参数可以将任务的PID一同显示出来。
和之前说的一样,+
标识的任务是最近操作的后台任务,-
标识的是第二近操作的后台任务,其它的后台任务就不会用特殊符号标识,只能通过任务编号去识别和操作。
让后台任务转到前台执行
可以通过fg
(foreground)命令让后台命令转移到前台并继续执行:
[root@xyz ~]# jobs -l
[1]- 3019 停止 vim ~/.bashrc
[2]+ 3020 停止 find / -print
[root@xyz ~]# fg
/proc/1266/task/1266/net/mcfilter
/proc/1266/task/1266/net/rt_cache
/proc/1266/task/1266/net/sockstat
/proc/1266/task/1266/net/udplite6^Z
[2]+ 已停止 find / -print
如果不指定任务编号,fg
将会操作最近的那个任务(带+
的任务)。
当然也可以操作指定编号的任务:
[root@xyz ~]# fg %1
vim ~/.bashrc
[1]+ 已停止 vim ~/.bashrc
[root@xyz ~]# jobs -l
[1]+ 3019 停止 vim ~/.bashrc
[2]- 3020 停止 find / -print
操作后+
和-
标识的任务会发生变化(这是理所当然的)。
此外可以通过fg +
或fg -
这样的方式执行最近和第二近的任务。
让任务在后台继续运行
可以使用bg
(background)命令让后台处于暂停状态的任务继续(在后台)运行:
[root@xyz ~]# find / -perm /7000 > /tmp/find.log 2>&1
^Z
[3]+ 已停止 find / -perm /7000 > /tmp/find.log 2>&1
[root@xyz ~]# jobs -l
[1]- 3019 停止 vim ~/.bashrc
[2] 3020 停止 find / -print
[3]+ 9925 停止 find / -perm /7000 > /tmp/find.log 2>&1
[root@xyz ~]# bg %3;jobs -l
[3]+ find / -perm /7000 > /tmp/find.log 2>&1 &
[1]+ 3019 停止 vim ~/.bashrc
[2] 3020 停止 find / -print
[3]- 9925 运行中 find / -perm /7000 > /tmp/find.log 2>&1 &
可以看到执行bg %3
后,不仅后台编号为3的任务状态变为了运行中
,而且所关联的命令结尾多了&
符号,这同样表示该命令在后台运行。
结束后台中的任务
有时候我们需要结束后台中的任务,这时候可以使用kill
这个命令,事实上这个命令主要用于管理进程,但任务其实也是一个进程,所以同样可以被kill
命令终止。
kill
命令终止进程的原理是向进程发送一个信号,进程会根据发送的信号类别做出相应的处理。具体包含以下信号:
[root@xyz ~]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
其中比较重要的有:
-
1) SIGHUP
:重启进程 -
9) SIGKILL
:强制终止进程 -
15) SIGTERM
:正常结束进程
其中kill -9
比较常用,如果需要强制结束进程,可以使用。需要注意的是,某些进程如果非正常退出会产生一些异常文件,比如vim
,会对再次执行产生一些额外影响。kill -15
是正常退出程序,但并不是所有进程都会在接收这个信号后无条件退出,比如vim
就会提示你应当使用内部命令q
的方式退出。
要终止指定的任务,可以这样:
[root@xyz ~]# jobs -l
[1]+ 3019 停止 vim ~/.bashrc
[2] 3020 停止 find / -print
[root@xyz ~]# kill -9 %2
[2] 已停止 find / -print
[root@xyz ~]# jobs -l
[1]+ 3019 停止 vim ~/.bashrc
[2] 3020 已杀死 find / -print
kill
在处理进程时是直接使用PID的,比如kill -9 3020
。处理任务则是使用任务编号,比如kill %2
。千万不能混为一谈。
脱机管理问题
正常情况下,我们对Linux主机的使用往往是通过ssh
之类的远程工具进行连接的,在这种情况下,如果我们要执行一个耗时比较长的命令,将其放在后台执行,如果断开连接后还会不会运行?
答案是不会,当我们的远程终端断开连接时,Linux主机会检查终端下的后台任务列表(jobs
命令输出的部分),并对其中正在运行的命令发出一个hangup
信号,之后进程就会处于挂起(Sleep
)状态,也就意味着不会继续执行。此外,因为终端所使用的Bash
进程会随着终端的断开而结束,所有的任务进程的PPID都会变为1,也就是将变为systemd
的子进程。
对于需要脱机后长时间执行的工作,可以使用其它方式执行,比如中介绍的at
命令,这个命令创建的定时任务是和终端无关的,是由atd
服务执行的,并不会受到终端断开影响,所以可以用来启动一个需要长时间脱机执行的命令。
此外还可以使用nohup
(no hangup)命令。这个命令本身是用来防止命令执行中被挂起的,通过该命令启动的命令在执行中会“免疫”hangup
信号,因此我们可以利用它创建一个不会受到终端断开而影响执行的后台任务:
[icexmoon@xyz tmp]$ vim sleep.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo 'already sleeped 500s'
exit 0
[icexmoon@xyz tmp]$ nohup sh /tmp/sleep.sh &
[1] 15862
[icexmoon@xyz tmp]$ nohup: 忽略输入并把输出追加到"nohup.out"
[icexmoon@xyz tmp]$ jobs
[1]+ 运行中 nohup sh /tmp/sleep.sh &
[icexmoon@xyz tmp]$ exit
这样做即使断开远程终端,通过nohup
启动的后台任务依然将运行。
其实还可以使用其它命令将任务移除后台任务列表,同样可以不再受到
hangup
信号的影响,具体详情可以阅读。
进程管理
查看进程
可以使用ps
(Process Status)命令查看系统中的进程信息。
查看当前Bash的进程
如果要查看当前终端的Bash产生了哪些进程,可以:
[icexmoon@xyz ~]$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 15164 15163 0 80 0 - 29279 do_wai pts/2 00:00:00 bash
0 R 1000 16372 15164 0 80 0 - 38331 - pts/2 00:00:00 ps
第一个出现的进程就是当前Bash
的进程。
输出的信息中各列所代表的含义为:
-
F
:进程标识(process flags),4
表示此进程权限为root
,1
表示此进程仅执行了fork
,没有执行exec
。 -
S
:进程状态:-
R
(Running):运行中或等待运行。 -
S
(Interruptible sleep):可被唤醒的睡眠状态。 -
D
(Uninterruptible sleep):不可被唤醒的睡眠状态,通常是进程在等待IO。 -
T
(Stopped):被任务控制暂停。 -
Z
(Zombie):僵尸进程。进程已经结束,但没有被其父进程回收。
-
-
UID
:进程所有者的UID -
PID
:进程编号 -
PPID
:父进程编号 -
C
:CPU使用率(百分比) -
PRI
:Priority,进程被CPU执行的优先级,数字越小优先级越高。 -
NI
:Nice,会影响优先级。 -
ADDR
:进程在内存中的地址,如果正在运行,会显示-
。 -
SZ
:进程占用的内存大小。 -
WCHAN
:进程是否正在运行,-
表示正在运行。 -
TTY
:启动进程所用的终端。 -
TIME
:运行进程花费的CPU时间。 -
CMD
:触发进程的命令。
查看系统的所有进程
如果要查看当前系统中的所有进程,可以:
[icexmoon@xyz ~]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.6 128400 6404 ? Ss 15:40 0:12 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root 2 0.0 0.0 0 0 ? S 15:40 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? S< 15:40 0:00 [kworker/0:0H]
root 6 0.0 0.0 0 0 ? S 15:40 0:08 [ksoftirqd/0]
root 7 0.0 0.0 0 0 ? S 15:40 0:00 [migration/0]
root 8 0.0 0.0 0 0 ? S 15:40 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? R 15:40 0:04 [rcu_sched]
root 10 0.0 0.0 0 0 ? S< 15:40 0:00 [lru-add-drain]
root 11 0.0 0.0 0 0 ? S 15:40 0:01 [watchdog/0]
root 13 0.0 0.0 0 0 ? S 15:40 0:00 [kdevtmpfs]
root 14 0.0 0.0 0 0 ? S< 15:40 0:00 [netns]
...省略...
root 16379 0.1 0.0 0 0 ? S 20:55 0:01 [kworker/0:2]
root 17352 0.0 0.0 0 0 ? S 21:11 0:00 [kworker/0:1]
root 17634 0.1 0.0 0 0 ? S 21:16 0:00 [kworker/0:0]
root 17805 0.1 0.0 0 0 ? R 21:19 0:00 [kworker/0:3]
root 17831 0.0 0.0 0 0 ? S 21:20 0:00 [kworker/u256:0]
第一个,PID为1的进程就是systemd
,这是Linux系统的主要进程。
这里输出的信息中各列的含义为(和ps -l
重复的字段不再一一说明):
-
USER
:进程拥有者的用户名 -
%MEM%
:进程占用的物理内存百分比 -
VSZ
:进程占用的虚拟内存大小(KB) -
RSS
:进程占用的物理内存大小(KB)
除了常用的ps aux
方式查看所有进程以外,还可以:
[icexmoon@xyz ~]$ ps -lA
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 0 80 0 - 32100 ep_pol ? 00:00:12 systemd
1 S 0 2 0 0 80 0 - 0 kthrea ? 00:00:00 kthreadd
1 S 0 4 2 0 60 -20 - 0 worker ? 00:00:00 kworker/0:0H
1 S 0 6 2 0 80 0 - 0 smpboo ? 00:00:09 ksoftirqd/0
1 S 0 7 2 0 -40 - - 0 smpboo ? 00:00:00 migration/0
...省略...
1 S 0 17634 2 0 80 0 - 0 worker ? 00:00:00 kworker/0:0
1 R 0 17805 2 0 80 0 - 0 ? ? 00:00:00 kworker/0:3
1 S 0 17831 2 0 80 0 - 0 worker ? 00:00:00 kworker/u256:0
1 S 0 18103 2 0 80 0 - 0 worker ? 00:00:00 kworker/0:1
1 S 0 18272 2 0 80 0 - 0 worker ? 00:00:00 kworker/0:2
0 S 0 18305 849 0 80 0 - 27013 hrtime ? 00:00:00 sleep
0 R 1000 18309 15164 0 80 0 - 38331 - pts/2 00:00:00 ps
输出的内容与ps aux
一样,不过风格与ps -l
一致。
此外,还可以通过ps
命令列出进程树,以观察进程之间的关系:
[icexmoon@xyz ~]$ ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 4 0 0 ? -1 S< 0 0:00 \_ [kworker/0:0H]
2 6 0 0 ? -1 S 0 0:09 \_ [ksoftirqd/0]
2 7 0 0 ? -1 S 0 0:00 \_ [migration/0]
2 8 0 0 ? -1 S 0 0:00 \_ [rcu_bh]
2 9 0 0 ? -1 R 0 0:04 \_ [rcu_sched]
...省略...
1 1763 1660 1660 ? -1 Sl 42 0:00 /usr/libexec/xdg-permission-store
1 1772 1772 1772 ? -1 Ssl 0 0:00 /usr/libexec/boltd
1 1779 1779 1779 ? -1 Ssl 0 0:01 /usr/libexec/packagekitd
1 1780 1780 1780 ? -1 Ss 0 0:00 /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplicant.log -c /etc/wpa_
1 1856 1856 1856 ? -1 Ssl 997 0:00 /usr/libexec/colord
除了查看所有进程,通常我们还需要将ps
与grep
命令结合起来,查找指定的进程:
[icexmoon@xyz ~]$ ps aux | egrep 'cron|rsyslog'
root 1245 0.0 0.4 214432 4296 ? Ssl 15:41 0:10 /usr/sbin/rsyslogd -n
root 1266 0.0 0.1 126380 1680 ? Ss 15:41 0:01 /usr/sbin/crond -n
icexmoon 18729 0.0 0.0 112824 988 pts/2 R+ 21:35 0:00 grep -E --color=auto cron|rsyslog
因为这里使用了正则高级语法,所以需要使用
egrep
而非grep
命令,或者也可以使用grep -E
。
动态查看进程变化
ps
命令只能一次性展示某一个时刻的进程情况,如果我们需要动态地查看系统中的进程情况(类似Windows的任务管理器),可以使用top
命令:
[icexmoon@xyz ~]$ top -d 2
top - 21:38:09 up 5:57, 1 user, load average: 0.02, 0.05, 0.05
Tasks: 185 total, 3 running, 182 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.5 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 995676 total, 82176 free, 553428 used, 360072 buff/cache
KiB Swap: 1048572 total, 1048308 free, 264 used. 247536 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 128400 6404 3564 S 0.0 0.6 0:13.13 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd
4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
6 root 20 0 0 0 0 S 0.0 0.0 0:09.17 ksoftirqd/0
7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
... 省略...
-d
参数可以执行top
输出信息的刷新时间间隔(秒),默认为5秒。按【q】可以退出。
top
输出的内容有两部分,上方为整个系统的基本情况,下方为具体进程的相关信息。
基本情况包含的信息有:
-
top
-
21:38:09 up 5:57
:当前时间为21:38:09
,本次开机已经运行了5小时57分。 -
1 user
:当前登录系统的有1个用户。 -
load average: 0.02, 0.05, 0.05
:CPU在最近的1、5、15分钟内的平均任务负载。
-
-
tasks
:-
185 total, 3 running, 182 sleeping, 0 stopped, 0 zombie
:共有185
个进程,3个运行中,182个睡眠中,0个被暂停,0个僵尸进程。
-
-
%Cpu(s)
:-
0.0 us
:用户模式占用的CPU百分比为0% -
0.5 sy
:系统模式占用的CPU百分比为0.5% -
0.0 ni
:改变过优先级的用户进程占用CPU的百分比为0% -
99.5 id
:空闲进程所占CPU的百分比为99.5%
-
0.0 wa
:等待输入、输出的进程占用CPU的百分比 -
0.0 hi
:硬件中断请求服务占用的CPU百分比 -
0.0 si
:软件中断请求服务占用CPU的百分比 -
0.0 st
:(steal time)虚拟时间百分比(在Linux主机上使用虚拟机时)
如果是多核处理器,可以按下数字键,如【1】切换不同的核心查看单个核心的使用状况。
-
-
KiB Mem
:物理内存的使用情况-
995676 total, 82176 free, 553428 used, 360072 buff/cache
:总共995676
KB,有82176
KB空闲,已经使用了553428
KB,缓存和缓冲数据占用360072
KB。
-
-
KiB Swap
:交换分区(Swap)的使用情况-
1048572 total, 1048308 free, 264 used. 247536 avail Mem
:总共有1048572
KB,有1048308
KB处于空闲状态,已使用264
KB
一般来说交换分区最好使用率低于20%为佳,否则说明你的物理内存不够用,需要扩容。
-
-
247536 avail Mem
:剩余的可用物理内存为247536
KB(包含了可以释放并回收的缓存数据占用的空间)
进程部分信息字段与ps
中相同,不再赘述。
此外,top
命令的输出是默认以CPU占用率进行排序,如果要以内存占用率进行排序,可以按【M】,如果要恢复为CPU占用率排序,可以按【P】。
如果要让top
产生瞬时数据,并保存到文件中,可以:
[icexmoon@xyz ~]$ top -b -n 2 > /tmp/top.txt
[icexmoon@xyz ~]$ less /tmp/top.txt
其中-b
参数为批量产生数据,会产生瞬时数据,-n
表示会输出两次(间隔5秒)。
此外,top
也可以监控指定进程:
[icexmoon@xyz ~]$ echo $$
15164
[icexmoon@xyz ~]$ top -d 2 -p 15164
top - 22:22:53 up 6:42, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%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
KiB Mem : 995676 total, 82252 free, 553164 used, 360260 buff/cache
KiB Swap: 1048572 total, 1048308 free, 264 used. 247800 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15164 icexmoon 20 0 117116 3640 1828 S 0.0 0.4 0:00.15 bash
这里
$$
变量中的值是当前Bash
的PID。
通过-p
参数可以指定具体的PID进行监控。
top
除了可以查看进程信息,也可以执行命令,比如在上一个演示中监控当前Bash进程以后,按下【r】:
top - 22:24:56 up 6:44, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
KiB Mem : 995676 total, 82252 free, 553160 used, 360264 buff/cache
KiB Swap: 1048572 total, 1048308 free, 264 used. 247804 avail Mem
PID to renice [default pid = 15164]
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15164 icexmoon 20 0 117116 3640 1828 S 0.0 0.4 0:00.15 bash
会出现提示信息PID to renice [default pid = 15164]
,按下【Enter】后会出现新的提示信息renice to xxxxx
,此时输入10
并按下【Enter】,就可以修改Bash
进程的nice
,此时top
再刷新后的信息就会变成:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15164 icexmoon 30 10 117116 3640 1828 S 0.0 0.4 0:00.16 bash
可以看到NI
的值已经改变,变为了10
。
pstree
虽然ps
可以输出进程树,但是我们有更专业的命令pstree
:
[icexmoon@xyz ~]$ pstree -up
systemd(1)─┬─ModemManager(781)─┬─{ModemManager}(791)
│ └─{ModemManager}(809)
├─NetworkManager(930)─┬─{NetworkManager}(936)
│ └─{NetworkManager}(940)
├─VGAuthService(756)
├─abrt-watch-log(754)
├─abrt-watch-log(775)
├─abrtd(751)
├─accounts-daemon(731)─┬─{accounts-daemon}(742)
│ └─{accounts-daemon}(817)
...省略...
├─crond(1266)
├─cupsd(1241)
├─dbus-daemon(1660,gdm)───{dbus-daemon}(1662)
├─dbus-daemon(787,dbus)───{dbus-daemon}(804)
├─dbus-launch(1654,gdm)
├─dnsmasq(1521,nobody)───dnsmasq(1522,root)
参数-u
的作用是输出进程所属的用户,-p
则为输出进程的PID。如果子进程与父进程是同一个用户,则用户名不会显示,如果不同才会显示,比如dnsmasq(1521,nobody)───dnsmasq(1522,root)
。
此外,默认情况下pstree
会使用Unicode
字符集输出结果,可能会在某些终端中出现连接线乱码的情况,此时可以尝试使用-A
参数解决,此参数将强制使用ASCII
字符作为连接线进行输出。
进程的管理
之前在介绍结束后台中的任务的时候有提到kill
这个命令,kill
不单单可以用于结束后台任务,也可以用于结束进程,同样是通过给进程传递一个信号的方式实现,经常会用到以下几种信号:
代号 | 名称 | 内容 |
---|---|---|
1 | SIGHUP | 启动被终止的进程,可以让该进程重新读取配置文件,类似重启 |
2 | SIGINT | 相当于使用【Ctrl+c】,中断程序的运行 |
9 | SIGKILL | 强制结束进程 |
15 | SIGTERM | 正常退出程序 |
19 | SIGSTOP | 相当于输入【Ctrl+z】,暂停一个运行中的程序 |
1、9、15是最为常用的。
kill
之前我们已经展示过如何使用kill
命令给任务发送信号,给进程发送信号的方式类似,不过不需要使用%
,而是直接指定PID即可,甚至我们还可以结合其它的管道命令使用:
[icexmoon@xyz ~]$ ps aux | grep rsyslogd | grep -v grep | awk '{print $2}'
1246
[icexmoon@xyz ~]$ sudo kill -1 $(ps aux | grep rsyslogd | grep -v grep | awk '{print $2}')
[icexmoon@xyz ~]$ sudo tail -n 5 /var/log/messages
Aug 29 11:27:51 xyz dbus[758]: [system] Successfully activated service 'org.freedesktop.problems'
Aug 29 11:30:02 xyz systemd: Created slice User Slice of root.
Aug 29 11:30:02 xyz systemd: Started Session 2 of user root.
Aug 29 11:30:02 xyz systemd: Removed slice User Slice of root.
Aug 29 11:35:13 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
从/var/log/messages
日志中的最后一行可以看出,rsyslogd
服务进程已经被重启了。
killall
除了使用kill
和PID操作指定的进程,还可以通过killall
命令以及命令名称操作相关的所有进程:
[icexmoon@xyz ~]$ sudo killall -1 rsyslogd
[icexmoon@xyz ~]$ sudo tail -n 5 /var/log/messages
Aug 29 11:35:13 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
Aug 29 11:40:01 xyz systemd: Created slice User Slice of root.
Aug 29 11:40:01 xyz systemd: Started Session 3 of user root.
Aug 29 11:40:01 xyz systemd: Removed slice User Slice of root.
Aug 29 11:40:43 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
[icexmoon@xyz ~]$ ps aux | grep httpd
icexmoon 2222 0.0 0.0 112824 976 pts/0 R+ 11:41 0:00 grep --color=auto httpd
[icexmoon@xyz ~]$ sudo killall -9 httpd
httpd: no process found
[icexmoon@xyz ~]$ sudo killall -i -9 bash
信号 bash(1938) ? (y/N) n
bash: no process found
killall
可以一次性操作所有指定命令启动的进程,如果需要在操作时进行类似信号 bash(1938) ? (y/N)
的提示,可以使用-i
参数。
关于进程的执行顺序
早期的CPU只会顺序执行给它的任务,也就是说必须等到一个程序全部执行完毕才能执行下一个程序,如果是科研项目还好说,如果是个人电脑,体验就极为糟糕了。所以现代操作系统就有了一个称作“CPU调度”的功能,即让CPU在执行任务的最基础单元划分为单条指令(CPU时钟),而将等待CPU执行的任务按CPU时钟进行分配,每个任务按照优先级高低分配不同的CPU时钟,在当前任务执行了所分配的CPU时钟后,无论有无执行完毕,都会执行任务切换,CPU会转而执行另一个任务。
这里边有一个概念就很重要:任务优先级。也就是之前我们所介绍的进程的优先级(Priority),这个值决定了给进程分配的CPU时钟的多少,也就是CPU计算资源的多少,优先级高必然代表着会更快地运行该程序。
Linux中,进程的优先级是由操作系统控制的,用户并不能直接修改,但是用户可以通过修改NI(nice)值来影响优先级,其中Priority与NI的关系是正相关,即NI值越大,Priority也越大(Priority越小优先级越高),NI越小Priority越小。其中NI的值为-20~19
,并且除了root
可以修改所有进程以外,一般用户只能修改自己进程的NI值,且只能修改为更大的NI值,且不能为负。
nice
可以使用nice
命令在命令执行时给与一个初始的NI值:
[root@xyz ~]# nice -n -5 vim &
[1] 3239
[root@xyz ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 3188 3143 0 80 0 - 57992 do_wai pts/0 00:00:00 su
4 S 0 3195 3188 0 80 0 - 29221 do_wai pts/0 00:00:00 bash
4 T 0 3239 3195 0 75 -5 - 36807 do_sig pts/0 00:00:00 vim
0 R 0 3240 3195 0 80 0 - 38331 - pts/0 00:00:00 ps
[1]+ 已停止 nice -n -5 vim
[root@xyz ~]# kill -9 3239
这里vim
命令启动的进程NI为-5
,PRI是75,优先级明显高于其它进程。
renice
使用renice
命令可以修改已经存在的进程的NI值:
[root@xyz ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 3188 3143 0 80 0 - 57992 do_wai pts/0 00:00:00 su
4 S 0 3195 3188 0 80 0 - 29272 do_wai pts/0 00:00:00 bash
0 R 0 3283 3195 0 80 0 - 38331 - pts/0 00:00:00 ps
[root@xyz ~]# renice -n -5 3195
3195 (进程 ID) 旧优先级为 0,新优先级为 -5
[root@xyz ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 3188 3143 0 80 0 - 57992 do_wai pts/0 00:00:00 su
4 S 0 3195 3188 0 75 -5 - 29272 do_wai pts/0 00:00:00 bash
0 R 0 3309 3195 0 75 -5 - 38331 - pts/0 00:00:00 ps
可以看到命令bash
所在的进程优先级被修改了。
此外需要注意的是ps
命令触发的进程的优先级也改变了,和bash
进程的优先级一样,这是因为ps
命令触发的进程是bash
所在进程的子进程,而子进程会继承父进程的优先级。
查看系统资源信息
除了ps
和top
命令外,还有一些其它命令可以查看系统的相关资源的情况。
free
free
命令可以用于查看系统内存的使用情况:
[root@xyz ~]# free -m
total used free shared buff/cache available
Mem: 972 489 110 10 372 318
Swap: 1023 0 1023
[root@xyz ~]# free -h
total used free shared buff/cache available
Mem: 972M 489M 110M 10M 372M 318M
Swap: 1.0G 0B 1.0G
free
可以输出物理内存和交换分区的使用情况,且可以指定输出数据的单位,比如-m
就是指输出的数据单位是MB
,也可以指定-b
、-k
、-g
等。也可以指定-h
,和df
命令类似。
uname
使用uname
命令可以查看系统内核的相关信息:
[root@xyz ~]# uname -a
Linux xyz.icexmoon.centos 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
使用-a
参数可以输出系统所有的信息,包括:
-
Linux
:内核名称 -
xyz.icexmoon.centos
:主机名 -
3.10.0-1160.el7.x86_64
:内核版本 -
SMP Mon Oct 19 16:18:59 UTC 2020
:内核版本构建时间 -
x86_64
:硬件架构平台
uptime
uptime
用于查看系统启动时间与任务负载:
[root@xyz ~]# uptime
16:11:35 up 1:53, 1 user, load average: 0.00, 0.02, 0.05
输出的信息表示:当前时间为16:11:35
,已经运行了1小时53分
,目前有1个登录用户,最近1、5、15分钟平均任务负载为0.00
、0.02
、0.05
。
netstat
netstat
可以用于追踪网络和socket文件,常用于网络监控:
[root@xyz ~]# netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 36 192.168.1.105:ssh icexmoon-book:8772 ESTABLISHED
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ] DGRAM 14024 /run/systemd/shutdownd
unix 3 [ ] DGRAM 9195 /run/systemd/notify
unix 2 [ ] DGRAM 9197 /run/systemd/cgroups-agent
unix 5 [ ] DGRAM 9208 /run/systemd/journal/socket
...省略...
unix 2 [ ] DGRAM 30055
unix 3 [ ] STREAM CONNECTED 33286 /run/dbus/system_bus_socket
unix 3 [ ] STREAM CONNECTED 33246
unix 2 [ ] DGRAM 50178
unix 3 [ ] STREAM CONNECTED 32969 /run/systemd/journal/stdout
unix 3 [ ] STREAM CONNECTED 33063 @/tmp/dbus-DRD7qNZ0s2
unix 3 [ ] STREAM CONNECTED 30489
unix 3 [ ] STREAM CONNECTED 30474
unix 3 [ ] STREAM CONNECTED 21389
unix 3 [ ] STREAM CONNECTED 33453 @/tmp/dbus-y72WF93R
unix 3 [ ] STREAM CONNECTED 30751 @/tmp/dbus-DRD7qNZ0s2
unix 3 [ ] STREAM CONNECTED 30456
netstat
输出的信息分为两部分,上边是本地LInux主机和外部的网络连接,下边是本机内互相之间进行通信进程。
第一部分相关的字段有:
-
Proto
:网络协议,分为TCP和UDP -
Recv-Q
:接收的数据量(非用户进程) -
Send-Q
:发送的数据量(非用户进程) -
Local Address
:本地IP和端口 -
Foreign Address
:远程IP和端口 -
State
:连接状态,主要有ESTABLISHED(建立连接)和LISTEN(监听)。
第二部分是本机内互相通信的进程,它们是通过 socket 文件实现的互相通信,具体的字段有:
-
Proto
:协议,一般为Unix
-
RefCnt
:连接到此Socket的进程数量 -
Flags
:连接标识 -
Type
:socket存取的类型,主要有STREAM和不需要确认的DGRAM两种(关系应该类似于TCP和UDP)。 -
State
:若为CONNECTED则表示多个进程之间的连系已建立。 -
Path
:连接到此Socket的相关进程的路径或相关数据的输出路径
有时候我们需要查看Linux主机上已经启动的正在监听端口的Web服务:
[root@xyz ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1577/master
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 739/rpcbind
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1483/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1241/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1243/cupsd
tcp6 0 0 ::1:25 :::* LISTEN 1577/master
tcp6 0 0 :::111 :::* LISTEN 739/rpcbind
...省略...
这几个参数的含义为:
-
t
:显示TCP连接 -
u
:显示UDP连接 -
l
:显示正在监听的连接 -
n
:显示端口(port number) -
p
:显示PID
dmesg
系统内核在启动和运行中,都会往内存中的受保护区域写入一些信息,dmesg
可以读取并输出这些信息:
[root@xyz ~]# dmesg | less
[root@xyz ~]# dmesg | grep sda
[ 9.181946] sd 0:0:0:0: [sda] 83886080 512-byte logical blocks: (42.9 GB/40.0 GiB)
[ 9.182083] sd 0:0:0:0: [sda] Write Protect is off
[ 9.182087] sd 0:0:0:0: [sda] Mode Sense: 61 00 00 00
[ 9.182424] sd 0:0:0:0: [sda] Cache data unavailable
[ 9.182427] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 9.470809] sda: sda1 sda2 sda3 sda4 sda5 sda6 sda7 sda8 sda9
[ 9.472461] sd 0:0:0:0: [sda] Attached SCSI disk
[ 19.067050] XFS (sda4): Mounting V5 Filesystem
[ 19.068455] XFS (sda2): Mounting V5 Filesystem
[ 19.241047] XFS (sda4): Ending clean mount
[ 20.607481] XFS (sda2): Ending clean mount
vmstat
vmstat
可以动态地报告内存、交换分区、CPU、I/O等的使用情况:
[root@xyz ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 112332 1080 381468 0 0 48 5 53 105 0 0 99 0 0
默认输出的是瞬时值,如果要每隔5秒报告一次,可以:
[root@xyz ~]# vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 111960 1080 381500 0 0 48 5 53 104 0 0 99 0 0
0 0 0 111960 1080 381500 0 0 0 18 54 91 0 0 100 0 0
0 0 0 111960 1080 381500 0 0 0 0 46 82 0 0 100 0 0
会一直输出,直到使用Ctrl+c
终止。
也可以每隔1秒报告3次:
[root@xyz ~]# vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 112084 1080 381504 0 0 48 5 53 104 0 0 99 0 0
0 0 0 112084 1080 381504 0 0 0 0 41 76 0 0 100 0 0
1 0 0 112084 1080 381504 0 0 0 0 41 72 0 1 99 0 0
其中各字段的含义为:
-
procs
:进程-
r
:等待运行的进程数量 -
b
:不能被唤醒的进程数量(等待I/O结果)
这两个值如果比较大表明系统的负载较高。
-
-
memory
:物理内存-
swpd
:使用的虚拟内存的容量 -
free
:空闲容量 -
buff
:缓冲容量 -
cache
:缓存容量
-
-
swap
:交换分区-
si
:从磁盘交换到内存的交换页数量,单位:KB/秒 -
so
:从内存交换到磁盘的交换页数量,单位:KB/秒
这两个值越大,表明系统在频繁地交换分页文件,是物理内存不够用地表现。
-
-
io
:-
bi
:从磁盘读入的区块数量,单位:块/秒 -
bo
:写入磁盘的区块数量,单位:块/秒
这两个值越大表明系统在进行忙碌的I/O操作。
-
-
system
:-
in
:每秒的中断数,包括时钟中断 -
cs
:每秒的环境(上下文)切换次数
-
-
CPU
:以CPU总使用时间的百分比显示-
us
:非内核层的CPU使用时间 -
sy
:内核的CPU使用时间 -
id
:空闲时间 -
wa
:等待I/O所花费的时间 -
st
:被虚拟机所使用的时间
-
此外,vmstat
也可以更进一步查看某个部分更详细的使用情况,比如查看磁盘:
[root@xyz ~]# vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
total merged sectors ms total merged sectors ms cur sec
sda 12126 34 798793 20318 2472 435 85113 12579 0 18
sr0 0 0 0 0 0 0 0 0 0 0
dm-0 10255 0 729805 18813 2838 0 72205 15725 0 17
dm-1 88 0 4408 46 0 0 0 0 0 0
dm-2 216 0 10326 354 61 0 4716 150 0 0
特殊文件与进程
具有SUID/SGID权限的命令的执行状态
之前在介绍目录和文件的权限管理时有提到过SUID和SGID,现在介绍了进程后,我们可以直接观察进程树:
[icexmoon@xyz ~]$ passwd
更改用户 icexmoon 的密码 。
为 icexmoon 更改 STRESS 密码。
(当前)UNIX 密码:#按下【Ctrl+z】后输入【Enter】
[1]+ 已停止 passwd
[icexmoon@xyz ~]$ pstree -uA
systemd-+-ModemManager---2*[{ModemManager}]
|-NetworkManager---2*[{NetworkManager}]
|-VGAuthService
|-2*[abrt-watch-log]
...省略...
|-sshd---sshd---sshd(icexmoon)---bash-+-passwd(root)
| `-pstree
...省略...
可以看到,因为passwd
具有SUID的权限,所以在被bash
启动后其拥有者从当前用户icexmoon
变为了passwd
这个可执行文件的拥有者root
。
/proc/*代表的意义
之前我们有说过/proc
目录其实是内存的映射,事实上内存中的进程以PID的形式存在于这个目录中:
[icexmoon@xyz ~]$ ll /proc | head -n 10
总用量 0
dr-xr-xr-x. 9 root root 0 8月 29 11:26 1
dr-xr-xr-x. 9 root root 0 8月 29 11:26 10
dr-xr-xr-x. 9 root root 0 8月 29 11:26 11
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1241
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1242
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1243
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1246
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1260
dr-xr-xr-x. 9 root root 0 8月 29 11:27 1272
其中/proc/1
这个目录就代表的是PID为1的进程,即systemd
:
[icexmoon@xyz ~]$ sudo ls -al /proc/1
总用量 0
dr-xr-xr-x. 9 root root 0 8月 29 11:26 .
dr-xr-xr-x. 200 root root 0 8月 29 11:26 ..
dr-xr-xr-x. 2 root root 0 8月 29 16:29 attr
-rw-r--r--. 1 root root 0 8月 29 17:09 autogroup
-r--------. 1 root root 0 8月 29 17:09 auxv
-r--r--r--. 1 root root 0 8月 29 11:26 cgroup
--w-------. 1 root root 0 8月 29 17:09 clear_refs
-r--r--r--. 1 root root 0 8月 29 11:26 cmdline
-rw-r--r--. 1 root root 0 8月 29 11:26 comm
-rw-r--r--. 1 root root 0 8月 29 17:09 coredump_filter
-r--r--r--. 1 root root 0 8月 29 17:09 cpuset
...省略...
其中cmdline
这个文件表示触发进程的命令行:
[icexmoon@xyz ~]$ sudo cat /proc/1/cmdline
/usr/lib/systemd/systemd--switched-root--system--deserialize22
environ
这个文件表示进程的环境变量。
对于整个Linux系统,相关的内容由以下文件构成:
文件 | 内容 |
---|---|
/proc/cmdline |
加载内核时执行的命令行 |
/proc/cpuinfo |
本机的CPU相关信息 |
/proc/devices |
系统各个主要设备的代号 |
/proc/filesystems |
目前已加载的文件系统 |
/proc/interrupts |
系统上的IRQ分配状态 |
/proc/ioports |
各设备配置的I/0端口 |
/proc/kcore |
内存 |
/proc/loadavg |
CPU的平均任务负载 |
/proc/meminfo |
内存使用情况 |
/proc/modules |
已加载的模块(驱动) |
/proc/mounts |
已挂载的文件系统 |
/proc/swaps |
交换分区 |
/proc/partitions |
硬盘分区 |
/proc/uptime |
系统运行情况 |
/proc/version |
内核版本 |
/proc/bus/* |
总线设备(包括USB设备等) |
文件关联
使用Windows稍微久点的同学肯定遇到过删除一个文件的时候提示该文件被某某进程占用,无法删除的情况。所以文件和进程是由关联性的,我们有时候需要找出某个进程正在使用的文件,或者某个文件正在被哪些进程使用。
fuser
fuser
(file user)可以根据文件找出正在使用该文件的进程:
[icexmoon@xyz ~]$ fuser -uv .
用户 进程号 权限 命令
/home/icexmoon: icexmoon 3143 ..c.. (icexmoon)bash
这里使用fuser
输出了当前使用~icexmoon
目录的相关进程。
参数-u
会同时显示进程的拥有者,-v
会显示进程和文件的完整相关性。
其中..c..
表示进程和文件的关联性,有这些可能的值:
-
c
:当前目录(非子目录) -
e
:可被触发为执行状态 -
f
:被开启的文件 -
r
:顶层目录(root derectory) -
F
:该文件被其它程序占用了,在等待响应中 -
m
:动态函数库(dll)
使用-m
参数可以查看某个目录所在的文件系统所关联的进程:
[root@xyz ~]# fuser -uv /proc
用户 进程号 权限 命令
/proc: root kernel mount (root)/proc
rtkit 756 .rc.. (rtkit)rtkit-daemon
[root@xyz ~]# fuser -muv /proc
用户 进程号 权限 命令
/proc: root kernel mount (root)/proc
root 1 f.... (root)systemd
root 491 f.... (root)systemd-journal
root 744 f.... (root)udisksd
rtkit 756 .rc.. (rtkit)rtkit-daemon
root 931 f.... (root)NetworkManager
root 1260 F.... (root)libvirtd
root 1307 F.... (root)X
gdm 1702 f.... (gdm)gnome-shell
root 1782 f.... (root)packagekitd
这对umount
时无法卸载很有用:
[root@xyz home]# cd ~
[root@xyz ~]# pwd
/root
[root@xyz ~]# umount /home
umount: /home:目标忙。
(有些情况下通过 lsof(8) 或 fuser(1) 可以
找到有关使用该设备的进程的有用信息)
[root@xyz ~]# fuser -muv /home
用户 进程号 权限 命令
/home: root kernel mount (root)/home
icexmoon 3143 ..c.. (icexmoon)bash
root 4060 ..c.. (root)passwd
可以清楚地看到,是有3个相关进程正在使用该文件系统,需要关闭bash
和passwd
两个进程后才可以卸载/home
这个文件系统,具体可以通过手动关闭进程,或者使用kill
命令。此外还可以:
[root@xyz ~]# fuser -mki /home
/home: 3143c 4060c 5031c
杀死进程 3143 ? (y/N) n
杀死进程 4060 ? (y/N) n
杀死进程 5031 ? (y/N) n
像上面展示地那样,使用-k
参数可以直接关闭相关联的进程(安全起见应该同时使用-i
参数)。
fuser
可以查看目录和文件系统关联的进程,当然也可以查看一个文件关联的进程:
[root@xyz ~]# find /run -type p
/run/dmeventd-client
/run/dmeventd-server
/run/systemd/inhibit/7.ref
/run/systemd/inhibit/6.ref
/run/systemd/inhibit/5.ref
/run/systemd/inhibit/4.ref
/run/systemd/inhibit/2.ref
/run/systemd/inhibit/1.ref
/run/systemd/sessions/31.ref
/run/systemd/sessions/13.ref
/run/systemd/sessions/c1.ref
/run/systemd/initctl/fifo
[root@xyz ~]# fuser -uv /run/systemd/sessions/c1.ref
用户 进程号 权限 命令
/run/systemd/sessions/c1.ref:
root 785 f.... (root)systemd-logind
root 1445 F.... (root)gdm-session-wor
lsof
lsof
(list open files)可以列出被进程所使用的文件名称:
[root@xyz ~]# lsof | head -n 10
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 253,0 236 64 /
systemd 1 root rtd DIR 253,0 236 64 /
systemd 1 root txt REG 253,0 1632776 25931100 /usr/lib/systemd/systemd
systemd 1 root mem REG 253,0 20064 8673004 /usr/lib64/libuuid.so.1.3.0
systemd 1 root mem REG 253,0 265576 9453934 /usr/lib64/libblkid.so.1.1.0
systemd 1 root mem REG 253,0 90248 8673000 /usr/lib64/libz.so.1.2.7
systemd 1 root mem REG 253,0 157424 8673022 /usr/lib64/liblzma.so.5.2.2
systemd 1 root mem REG 253,0 23968 8673015 /usr/lib64/libcap-ng.so.0.0.0
systemd 1 root mem REG 253,0 19896 8693416 /usr/lib64/libattr.so.1.1.0
默认将输出所有使用文件的进程。如果仅要列出root
所属的使用socket文件的进程:
[root@xyz ~]# lsof -u root -a -U
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 12u unix 0xffff99943fbea200 0t0 13919 /run/systemd/private
systemd 1 root 13u unix 0xffff99941d449dc0 0t0 31103 /run/systemd/journal/stdout
systemd 1 root 15u unix 0xffff99941d44b300 0t0 31104 /run/systemd/journal/stdout
systemd 1 root 16u unix 0xffff999417239540 0t0 32172 /run/systemd/journal/stdout
systemd 1 root 17u unix 0xffff999417239dc0 0t0 32173 /run/systemd/journal/stdout
systemd 1 root 18u unix 0xffff99941723e1c0 0t0 32203 /run/systemd/journal/stdout
systemd 1 root 20u unix 0xffff99943fbebfc0 0t0 13997 /run/lvm/lvmpolld.socket
...省略...
其中参数-u
用于指定进程的所属用户,-U
参数是指定使用了UNIX socket file
的进程,-a
参数是可以让输出的结果必须要同时满足所有的参数条件(相当于and
,默认情况下各参数之间的关系是or
)。
如果要查看系统上所有被使用的外接设备:
[root@xyz ~]# lsof +d /dev | head -n 10
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 0u CHR 1,3 0t0 6513 /dev/null
systemd 1 root 1u CHR 1,3 0t0 6513 /dev/null
systemd 1 root 2u CHR 1,3 0t0 6513 /dev/null
systemd 1 root 30u unix 0xffff99943fbe9980 0t0 9210 /dev/log
systemd 1 root 34r CHR 10,235 0t0 8682 /dev/autofs
kdevtmpfs 13 root cwd DIR 0,5 3480 3 /dev
kdevtmpfs 13 root rtd DIR 0,5 3480 3 /dev
systemd-j 491 root 0r CHR 1,3 0t0 6513 /dev/null
systemd-j 491 root 1w CHR 1,3 0t0 6513 /dev/null
-d
参数用于输出顶级目录的结果,不会降目录。
如果要查找root
用户下bash
相关的进程:
[root@xyz ~]# lsof -u root | grep bash
ksmtuned 863 root txt REG 253,0 964536 34262 /usr/bin/bash
bash 4439 root cwd DIR 253,0 254 25165889 /root
bash 4439 root rtd DIR 253,0 236 64 /
bash 4439 root txt REG 253,0 964536 34262 /usr/bin/bash
...省略...
pidof
pidof
命令的用途很简单,就是获取指定命令的PID:
[root@xyz ~]# pidof systemd rsyslogd
1 1246
[root@xyz ~]# pidof bash
5091 5031 4439 3143 863
这个命令可以结合其它命令一起使用。
关于进程管理的内容就介绍到这里,谢谢阅读。
参考资料
文章评论