Linux入门之进程管理(4)之进程与文件

前面使用进程相关命令管理工具都是根据进程编号或者进程名称及其其它属性信息来查看和处理相关进程的,但是在某些情况下,想要查看某个文件或者某个设备被哪些进程所使用,使用ps、pgrep等命令查询的是不够准确的,而且有些时候并不是简单的去打开某个文本文件一样,这样还可以进行搜索过滤出来。而在linux系统中,除了常见的配置文件、日志文件等文本文件,几乎任何对象都会被内核映射去该有的文件,比如磁盘设备、挂载点等。当要知道那些用户通过哪些进程来在访问或者使用此文件时,就需要通过向文件的方式去查找其来链接的进程了。

 

linux软件包中也提供了一些相关命令来解决:fuser lsof

fuser  命令

fuser - identify processes using files or sockets

通过文件或者套接字文件来识别器对应的进程

选项与参数:

fuser  [-umv] [-k [i] [signal]] file/dir

-u除了进程的PID之外,同时列出该进程的拥有者;

-m后面接的那个文件名会主动的上提到该文件系统的最顶层,对于umount不成功很有效

-v可以列出每个文件与进程还有指令的完整相关性;

-k找出该文件/目录的PID,并对与其PID对应的进程发送SIGKILL信号;

-i必须与 -k 配合,在删除PID 之前会先询问使用者,交互式;

-signal例如 -l -15 指定信号代码,不指定默认为SIGKILL(-9)信号。

 

使用案例:

1、显示信息字段介绍

#找出对当前所在目录的进行使用的进程的PID、所属用户、权限

[root@localhost ~]# fuser -uv .
                  USER       PID ACCESS COMMAND
/root:               root      13357 ..c.. (root)bash
                  root      14154 ..c.. (root)bash


解析:这里当前目录在root家目录,有两个PID也就是两个进程号分别为13357、14154的进程在访问此目录,此进程所属用户为root,并且进程指令为bash。在ACCESS访问的那一列有很多字符,下面一一介绍:

ACCESS:

c    current directory.         #当前所在此目录

e    executable being run.      #已经运行的执行文件

f    open file.  f is omitted in default display mode.    #被打开的文件

F    open file for writing.  F is omitted in default display mode.  

    #该文件被开启,但是在等待回应中


r    root directory.          #代表顶级目录(root directory)

m    mmap'ed file or shared library.  #可能为分享的动态函数库

 

 

2、指定目录或文件访问进程列表查看

查看某个文件系统下有多少个进程正在占用该文件,使用-m选项指定挂载点

#开启另一个终端bash进程来备份当前关盘镜像

[root@localhost ~]# dd if=/dev/cdrom of=/test/mk.iso

#回到刚才终端查看/dev/cdrom设备

[root@localhost ~]# fuser -uv /dev/cdrom 
                USER        PID ACCESS COMMAND
/dev/sr0:            root      14756 f.... (root)dd

说明:f表示是一个被开启的文件,因为要读取光盘数据,肯定是会打开访问的。

#查看/proc虚拟文件系统挂载点又多少进程在访问

[root@localhost ~]# fuser -muv /proc/  
                  USER           PID ACCESS COMMAND
/proc:               root           kernel mount (root)/proc
                  root          1 f.... (root)systemd
                  root          2 ...e. (root)kthreadd
                  root          3 ...e. (root)ksoftirqd/0
                  root          5 ...e. (root)kworker/0:0H
                  root          7 ...e. (root)migration/0
                  root          8 ...e. (root)rcu_bh
                  root          9 ...e. (root)rcuob/0


 

3、查看指定目录访问用户及进程

查看所有使用到/home这个文件系统的进程

#使用另一个终端用hadoop并切换到用户家目录

[root@localhost ~]# su - hadoop
[hadoop@localhost ~]$ whoami
hadoop
[hadoop@localhost ~]$ pwd
/home/hadoop

#查看当前所在的bash进程

[hadoop@localhost ~]$ echo $$
14803

#使用fuser 命令查询出/home下访问的进程指令及用户和PID

[hadoop@localhost ~]$ fuser -muv ..
                     USER        PID ACCESS COMMAND
/home:               root     kernel mount (root)/
                     hadoop    14803 .rce. (hadoop)bash

解析:这里显示了当前hadoop开启的PID为14803的bash进程,下面用pidof来确认。

#使用pidof确认当前所在会话进程

[hadoop@localhost ~]$ pidof -s bash
14803

说明:这里的进程的发起者为hadoop和其访问目录,/home本身为/目录的目录,rce则表示此当前已经在此目录中,并且正在打开使用中,因为hadoop在/home/hadoop下,当然已经进入了,且为顶级目录。

 

4、挂载点目录的强制卸载

当有时候因为有内存中大量的数据尚未写入到文件系统的挂载点中,但是又想要卸载此挂载点,这时就可以用到-k和-m选项来指导挂载点并强制停止挂载点的使用。

#查询新建的/dev/sda3分区的挂载点为/test目录

[root@localhost ~]# findmnt /dev/sda3
TARGET SOURCE    FSTYPE OPTIONS
/test  /dev/sda3 ext4   rw,relatime,seclabel,data=ordered

#下面对此目录进行大连读写操作

[root@localhost ~]# tar -jcf  /test/iso.bak  /mnt/Packages/* &

#确定此进程仍在后台运行

[root@localhost ~]# jobs
[1]+  Running                 tar -jcf /test/iso.bak /mnt/Packages/* &

#使用umount卸载/test挂载点

[root@localhost ~]# umount /test/
umount: /test: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

说明:这里闲了了target is busy表示此挂载点目录正在被使用中,所以无法卸载,在以往可以使用pkill、pgrep等命令来查看tar相关进程并进行kill -9来强制杀掉此进程,但是如果使用pkill或者pgrep的-f选项来完整过滤命令行是很难精确匹配的,如果在多个终端上都有此访问,可能会误杀。

 

#因此使用fuser直接找到对应的文件目录的进程PID

[root@localhost ~]# fuser -muv /test/
                     USER        PID ACCESS COMMAND
/test:               root     kernel mount (root)/test
                     root      14877 F.... (root)bzip2

说明:这里显示了F说明此目录并每人进入范围而是后台对其操作。并且显示的确定命令居然显示不是tar命令,而是bzip2命令,这就更好解释了,因为tar -j命令就是调用bzip2命令进行对归档文件的压缩。对此可以判断通过这里可以看到最直接的命令调用。

#使用-k默认发送-9信号,-m将/test目录排队到文件系统映射的最前面,这样杀死对目录有访问有关的所有进程都会杀死。

[root@localhost ~]# fuser -km /test
/test:               14877

#再次查看/test目录下的进程,只有最基本的系统内核的文件系统了

[root@localhost ~]# fuser -muv /test/
                     USER        PID ACCESS COMMAND
/test:               root     kernel mount (root)/test

#下面直接卸载,没有提示错误或警告

[root@localhost ~]# umount /test

#再次查看当前挂载点中,通过与运算符判断输出,已经被卸载掉了

[root@localhost ~]# mount | grep '\</test/\>' && echo 'mountpoint such' || echo 'mountpoint no such'
mountpoint no such

 

 

lsof  命令

lsof - list open files

fuser查看文件的相关进程信息相反,此命令是通过进程来列出对应进程所在使用的文件。

选项与参数:

lsof  [-aUn]  [+d]

-a多项数据需要同时成立才显示出结果,类似find中-a的作用;

-U仅列出unix like 相关的 socket  文件类型;

-uuname列出指定进程的生效者所开启的文件;

+ddirpath找出指定目录下已经被开启的文件;

 

使用案例:

#列出当前系统上面所有被开启的文件

[root@localhost ~]# lsof

wKioL1fkAYWQ2wooAABBQVJhP6U061.png 

说明:这里的信息与ps直接列出的信息有些相识,只是CMMADN列为直接调用的命令名,而

NAME则表示了被开启的文件的完整路径。DEVICE列还显示了对应的文件所在文件系统的主设备号和此设备号。USER显示了使用的用户,TYPE显示了此文件的类型。还有NODE此列表示文件对应的indoe编号。

#累出关于root的所有进程开启的socket文件

[root@localhost ~]# lsof -u root -a -U

wKioL1fkAZfAexgkAAA1Fm3mFlc158.png 

解析:因为套接字为进程间通信时临时产生,所有为内存中的临时文件,这里的DEVICE表示了每个套接字文件对应的其唯一的标识符号。

#列出所有系统上列出的被启动的周边装载

[root@localhost ~]# lsof +d /dev

wKiom1fkAa3jXcrmAAAgeuFt0LU304.png 

#配合grep过滤出只属于root用户咋在bash进程所开启的文件

[root@localhost ~]# lsof -u root | grep '\<bash\>'

wKiom1fkAcWwtwnEAABaxwmvBm4612.png