Linux下 lsof 命令詳解

Linux下 lsof 命令詳解

lsof 是 List Open File 的縮寫, 它主要用來獲取被程序開啟檔案的資訊,我們都知道,在Linux中,一切皆檔案,lsof命令可以檢視所有已經打開了的檔案,比如: 普通檔案,目錄,特殊的塊檔案,管道,socket套接字,裝置,Unix域套接字等等,同時,它還可以結合 grep 以及 ps 命令進行更多的高階搜尋

安裝

lsof 命令預設是沒有安裝的,而且它的使用需要有root許可權或者賦予普通用於sudo許可權, 使用以下命令安裝

yum install -y lsof

lsof 命令有很多可選引數,本文根據我自己的使用經驗整理了一些比較常用且重要的用法

列出所有開啟的檔案

不帶任何引數執行 lsof 命令會輸出當前所有活躍程序開啟的所有檔案

[root@ecs-centos-7 ~]# lsof | moreCOMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAMEsystemd 1 root cwd DIR 253,1 4096 2 /systemd 1 root rtd DIR 253,1 4096 2 /systemd 1 root txt REG 253,1 1624520 530313 /usr/lib/systemd/systemdsystemd 1 root mem REG 253,1 20064 528340 /usr/lib64/libuuid。so。1。3。0systemd 1 root mem REG 253,1 265600 532853 /usr/lib64/libblkid。so。1。1。0systemd 1 root mem REG 253,1 90248 525942 /usr/lib64/libz。so。1。2。7systemd 1 root mem REG 253,1 157424 525955 /usr/lib64/liblzma。so。5。2。2systemd 1 root mem REG 253,1 23968 526159 /usr/lib64/libcap-ng。so。0。0。0systemd 1 root mem REG 253,1 19896 526135 /usr/lib64/libattr。so。1。1。0systemd 1 root mem REG 253,1 19288 525996 /usr/lib64/libdl-2。17。sosystemd 1 root mem REG 253,1 402384 525931 /usr/lib64/libpcre。so。1。2。0systemd 1 root mem REG 253,1 2156160

由於lsof命令會輸出很多資訊,所以上面例子中使用了 lsof | more 來分頁顯示命令輸出結果

輸出結果中,第一列中 systemd 的程序ID是 1,它是一個守護程序

其中列 COMMAND 、PID、USER 分別表示程序名、程序ID、所屬使用者

列 FD 是檔案描述符,下面是可能的型別以及說明

FD

說明

cwd

當前目錄

txt

txt檔案

rtd

root目錄

mem

記憶體對映檔案

列 TYPE 是檔案型別,下面是可能的值以及說明

TYPE

說明

DIR

目錄

REG

普通檔案

CHR

字元

a_inode

Inode檔案

FIFO

管道或者socket檔案

netlink

網路

unknown

未知

列 DEVICE 表示裝置ID

列 SIZE/OFF 表示程序大小

列 NODE 表示檔案的Inode號

列NAME 表示路徑或者連結

列出指定使用者已開啟的檔案

使用 -u 選項可以列出指定使用者已經開啟的檔案,該選項後面可以接多個使用者名稱,每個使用者名稱之間用空格隔開,表示列出所有指定使用者已開啟的所有檔案

[root@ecs-centos-7 ~]# lsof -u tt | moreCOMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEbash 27789 tt cwd DIR 253,1 4096 131090 /home/ttbash 27789 tt rtd DIR 253,1 4096 2 /bash 27789 tt txt REG 253,1 964600 525779 /usr/bin/bashvim 27813 tt txt REG 253,1 2337192 531847 /usr/bin/vimvim 27813 tt 4u REG 253,1 12288 131167 /home/tt/。p。txt。swp

上面的例子中,lsof -u tt 命令表示列出 tt 使用者已經打開了的檔案,從結果可以看出,使用者打開了 /home/tt、/、/usr/bin/bash、/usr/bin/vim、/home/tt/。p。txt。swp 這幾個檔案

如果要排除指定使用者已經開啟的檔案,可以在使用者名稱前加 ^ 符號,下面的命令會列出除tt使用者外其他所有使用者已打開了的檔案

lsof -u ^tt | more

找出開啟著但已被刪除了的檔案

有這樣一種場景,有一個服務正在往日誌檔案中寫日誌,這個時候,不小心把正在寫入的日誌檔案刪除了

上面的場景中,日誌檔案雖然被刪除了,但是檔案仍然是開啟著的,它仍然佔用檔案系統的空間,我們可以結合 grep 命令找出這種開啟著,但是已經被刪除的檔案

[root@ecs-centos-7 ~]# lsof -u tt | grep deletedvim 27813 tt 4u REG 253,1 12288 131167 /home/tt/。p。txt。swp(deleted)

上面例子中使用 lsof -u tt | grep deleted 命令檢視使用者 tt開啟著的確被刪除的檔案

從結果可以看出,在往 p。txt寫入內容的時候,檔案被刪除了

列出所有打開了的網路檔案

[root@ecs-centos-7 ~]# lsof -iCOMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEntpd 567 ntp 18u IPv4 12657 0t0 UDP localhost:ntpntpd 567 ntp 22u IPv6 16095 0t0 UDP ecs-centos-7。4-64bit-20200212:ntp dhclient 651 root 6u IPv4 14594 0t0 UDP *:bootpc master 960 root 13u IPv4 15791 0t0 TCP localhost:smtp (LISTEN)master 960 root 14u IPv6 15792 0t0 TCP localhost:smtp (LISTEN)mysqld 1053 mysql 13u IPv6 15147 0t0 TCP *:mysql (LISTEN)sshd 1348 root 3u IPv4 16698 0t0 TCP *:ssh (LISTEN)

列出所有 IPV4/6 網路檔案

列出所有已經打開了的 ipv4 網路檔案

[root@ecs-centos-7 ~]# lsof -i 4COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEntpd 567 ntp 16u IPv4 12651 0t0 UDP *:ntp ntpd 567 ntp 18u IPv4 12657 0t0 UDP localhost:ntp ntpd 567 ntp 21u IPv4 16094 0t0 UDP ecs-centos-7。4-64bit-20200212:ntp dhclient 651 root 6u IPv4 14594 0t0 UDP *:bootpc master 960 root 13u IPv4 15791 0t0 TCP localhost:smtp (LISTEN)sshd 1348 root 3u IPv4 16698 0t0 TCP *:ssh (LISTEN)

所有已經打開了的 ipv6 網路檔案

[root@ecs-centos-7 ~]# lsof -i 6COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEntpd 567 ntp 17u IPv6 12652 0t0 UDP *:ntp ntpd 567 ntp 19u IPv6 12658 0t0 UDP localhost:ntp ntpd 567 ntp 22u IPv6 16095 0t0 UDP ecs-centos-7。4-64bit-20200212:ntp master 960 root 14u IPv6 15792 0t0 TCP localhost:smtp (LISTEN)mysqld 1053 mysql 13u IPv6 15147 0t0 TCP *:mysql (LISTEN)sshd 1348 root 4u IPv6 16700 0t0 TCP *:ssh (LISTEN)

列出在指定埠上開啟的檔案

使用 lsof -i:埠號 可以獲得所有在指定埠號上開啟的檔案

[root@ecs-centos-7 ~]# lsof -i:22COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEsshd 1348 root 3u IPv4 16698 0t0 TCP *:ssh (LISTEN)sshd 1348 root 4u IPv6 16700 0t0 TCP *:ssh (LISTEN)sshd 27741 root 3u IPv4 458958 0t0 TCP ecs-centos-7。4-64bit-20200212:ssh->113。118。121。220:42395 (ESTABLISHED)sshd 27819 root 3u IPv4 459250 0t0 TCP ecs-centos-7。4-64bit-20200212:ssh->113。118。121。220:19807 (ESTABLISHED)sshd 27895 root 3u IPv4 459828 0t0 TCP

上面例子列出了所有在22號埠上開啟的檔案

在伺服器開發中,經常會部署一個閘道器或者代理程式,用來和客戶端通訊,閘道器或者代理程式需要開放一個固定的埠供客戶端連線用

如果客戶端連線不上閘道器或者代理程式,我們可以用上述命令檢查閘道器或代理程式的埠是否開啟,來排除因為埠關閉了導致連線不上閘道器的情況

列出使用了指定協議(TCP/UDP) 的檔案

使用 lsof -i TCP/UDP 列出使用了TCP 或 UDP 協議的檔案

[root@cghost8 /home/cgyx]# lsof -i TCP | moreCOMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEsshd 1704 root 3u IPv4 13593 0t0 TCP *:ssh (LISTEN)sshd 1704 root 4u IPv6 13595 0t0 TCP *:ssh (LISTEN)redis-serer 1725 root 4u IPv4 19773 0t0 TCP localhost:6380 (LISTEN)nc 2067 cgyx 4u IPv4 39167 0t0 TCP *:60600 (LISTEN)mysqld 3020 mysql 4u IPv6 5514608 0t0 TCP 192。168。70。10:mysql->192。168。70。10:37084 (ESTABLISHED)

使用 lsof -i TCP:3306 列出使用了TCP 協議並且埠為3306的檔案

[root@cghost8 /home/cgyx]# lsof -i TCP:3306COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEmysqld 3020 mysql 4u IPv6 5514608 0t0 TCP 192。168。70。10:mysql->192。168。70。10:37084 (ESTABLISHED)

使用 lsof -i TCP:1-1024 列出使用了TCP協議並且埠範圍為 1 到 1024 的檔案

[root@cghost8 /home/cgyx]# lsof -i TCP:1-1024COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEsshd 1704 root 3u IPv4 13593 0t0 TCP *:ssh (LISTEN)sshd 1704 root 4u IPv6 13595 0t0 TCP *:ssh (LISTEN)cupsd 1709 root 12u IPv6 39148 0t0 TCP localhost:ipp (LISTEN)cupsd 1709 root 13u IPv4 39149 0t0 TCP localhost:ipp (LISTEN)smbd 1824 root 35u IPv6 17658 0t0 TCP *:microsoft-ds (LISTEN)smbd 1824 root 36u IPv6 17659 0t0 TCP *:netbios-ssn (LISTEN)smbd 1824 root 37u IPv4 17660 0t0 TCP *:microsoft-ds (LISTEN)smbd 1824 root 38u IPv4 17661 0t0 TCP *:netbios-ssn (LISTEN)

列出目錄中所有開啟的檔案

可以使用lsof命令列出指定目錄中的所有開啟檔案

現有一個data目錄 ,結構如下:

[root@ecs-centos-7 tt]# tree data/data/├── dira│ └── a。txt└── d。s1 directory, 2 files

列出 data 目錄中開啟的檔案

[root@ecs-centos-7 tt]# lsof +D 。/data/COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEbash 28473 root cwd DIR 253,1 4096 131146 。/databash 28502 root cwd DIR 253,1 4096 131172 。/data/diravim 28530 root cwd DIR 253,1 4096 131172 。/data/diravim 28530 root 4u REG 253,1 12288 131174 。/data/dira/。a。txt。swp[root@ecs-centos-7 tt]# lsof +d 。/data/COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEbash 28473 root cwd DIR 253,1 4096 131146 。/databash 28502 root cwd DIR 253,1 4096 131172 。/data/diravim 28530 root cwd DIR 253,1 4096 131172 。/data/dira

上面例子中,+D 和 +d 選項都是列出目錄中開啟的檔案

+D 選項會列出一個目錄和其子目錄中開啟的檔案,而 +d 選項只會列出當前目錄下已開啟的檔案

列出指定程序ID開啟的檔案

程序ID是作業系統程序的唯一標識,以下命令列出了程序ID為 1053 相關的檔案, 從結果中可以知道這個程序ID對應的程序是MySQL

[root@ecs-centos-7 ~]# lsof -p 1053COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEmysqld 1053 mysql cwd DIR 253,1 4096 1055765 /var/lib/mysqlmysqld 1053 mysql rtd DIR 253,1 4096 2 /mysqld 1053 mysql txt REG 253,1 251841448 534935 /usr/sbin/mysqldmysqld 1053 mysql mem REG 253,1 209512 659436 /usr/lib64/mysql/plugin/validate_password。somysqld 1053 mysql 1w REG 253,1 206658 924771 /var/log/mysqld。logmysqld 1053 mysql 2w REG 253,1 206658 924771 /var/log/mysqld。log

上述命令中,-p 選項後面可以指定多個程序ID,每個程序ID之間用逗號分隔,如果想排除掉某個程序開啟的檔案,可以在該程序ID前面加上 ^符號

lsof -p 1,2,3,^4

上述命令會列出程序1,程序2,程序3開啟的所有檔案,同時忽略程序4開啟的檔案

殺死指定使用者的所有程序

前面介紹了列出指定使用者所有開啟的檔案,我們可以組合 kill 命令一起使用,實現殺死指定使用者的所有程序的功能,具體的命令如下

kill -9 `lsof -t -u tt`

上述命令中,lsof -u tt 是列出tt使用者所有開啟的檔案,加上 -t 選項之後表示結果只列出PID列,也就是程序ID列,其他列都忽略,前面的 kill -9 表示強制結束指定的程序ID

小結

本文介紹了 lsof 命令的一些常見用法,它還有很多其他的用法,請自行檢視man文件