lsof(List Open Files)是 Linux 系統內視鏡,將「一切皆文件」的哲學具象化:普通文件、目錄、網絡套接字、設備、管道、共享庫、inode……通過文件描述符表,lsof 能精準回答「誰在用這個文件/端口?」「這個進程打開了什麼?」本文從輸出解讀、高頻參數、實戰場景到進階腳本化,構建完整 lsof 技能樹。
[root@localhost ~]# lsof -p 1234
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1234 root cwd DIR 8,2 4096 2 /
nginx 1234 root rtd DIR 8,2 4096 2 /
nginx 1234 root txt REG 8,2 123456 1234567 /usr/sbin/nginx
nginx 1234 root mem REG 8,2 2345678 2345678 /lib/x86_64-linux-gnu/libc-2.31.so
nginx 1234 root 10u FIFO 0,17 0 123 /run/nginx.sock
nginx 1234 root 11u IPv4 1234567 0t0 TCP *:80 (LISTEN)
nginx 1234 root 12u IPv6 1234568 0t0 TCP *:80 (LISTEN)
| 欄位 | 含義 | 關鍵值解析 |
|---|---|---|
| COMMAND | 進程名(前 15 字符) | |
| PID | 進程 ID | |
| USER | 進程擁有者 | |
| FD | 文件描述符 | cwd(工作目錄) rtd(根目錄) txt(程式碼段) mem(記憶體映射文件) NUM[urw](數字 FD: u=讀寫 r=只讀 w=只寫) |
| TYPE | 文件類型 | REG(普通) DIR(目錄) CHR(字符設備) BLK(塊設備) FIFO(管道) SOCK(Socket) IPv4/6(網絡) unix(域套接字) |
| DEVICE | 設備號 (主,次) | ls -l /dev | grep "主, 次" 反查設備 |
| SIZE/OFF | 文件大小/偏移量 | |
| NODE | inode 號 | find -inum NODE 定位文件 |
| NAME | 文件路徑/網絡地址 | Socket 顯示 IP:PORT (STATE) |
| 參數 | 功能 | 典型組合 |
|---|---|---|
-p PID | 顯示指定 PID 打開的文件 | lsof -p 1234 |
-c 進程名 | 顯示指定命令名的進程打開的文件 | lsof -c nginx |
-u 用戶 | 顯示指定用戶的進程打開的文件 | lsof -u www-data |
-i [條件] | 網絡連接過濾神器 | 見下文詳解 |
-d FD | 顯示佔用指定 FD 的進程 | lsof -d 80 |
+d 目錄 | 列出目錄下被打開的文件(不遞歸) | lsof +d /var/log |
+D 目錄 | 遞歸列出目錄下被打開的文件 | lsof +D /home |
-n | 不解析主機名(加速輸出) | 生產環境必加 |
-P | 不解析服務名(顯示埠號而非 http/ssh) | 生產環境必加 |
-t | 僅輸出 PID(適配腳本殺進程) | kill -9 $(lsof -t -i :8080) |
-r 秒數 | 重複模式,每隔秒數刷新 | lsof -r 2 -i :80 |
+L1 | 顯示鏈接計數為 0 的文件(**刪除但未釋放磁碟空間的幽靈文件**) | lsof +L1 |
-a | 條件 AND 邏輯(預設 OR) | lsof -a -c nginx -i :80 |
-i 參數深度解析:網絡連接精準過濾
# 基礎語法: -i[4/6][協議][@主機][:端口/服務名]
# 4/6: IPv4/IPv6
# 協議: tcp, udp, sctp
# 主機: IP 或主機名
# 端口: 數字、範圍、服務名
lsof -i # 所有網絡連接
lsof -i tcp # 所有 TCP 連接
lsof -i udp # 所有 UDP 連接
lsof -i :80 # 佔用埠 80 的進程 (TCP+UDP)
lsof -i tcp:80 # 佔用 TCP 80
lsof -i udp:53 # 佔用 UDP 53
lsof -i :8000-9000 # 埠範圍
lsof -i @192.168.1.100 # 連接到該 IP 的進程
lsof -i @192.168.1.100:80 # 連接到該 IP:埠
lsof -i tcp@10.0.0.1:22 # TCP 連接到 10.0.0.1:22
lsof -i udp@[2001:db8::1]:53 # IPv6 UDP
# 快速定位佔用 8080 埠的進程並殺掉
lsof -i :8080
# 或僅輸出 PID 直接殺掉
kill -9 $(lsof -t -i :8080)
# 查看具體連接狀態
lsof -i -n -P | grep :8080
# 統計進程打開文件數
lsof -p 1234 | wc -l
# 找出打開文件最多的前 10 個進程
lsof -n | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
# 檢查是否有大量 CLOSE_WAIT 狀態 Socket (應用層未正確關閉)
lsof -i -n -P | awk '/CLOSE_WAIT/ {print $1,$2,$9}' | sort | uniq -c | sort -rn
# 現象: df 顯示滿, du 顯示少 -> 有進程持有已刪除文件
lsof +L1
# 輸出 NLINK=0 的文件, 找到對應 PID
# 解決: 重啟該進程或發送信號觸發關閉 FD
kill -HUP # 若應用支援熱加載
# 或強制關閉 FD (GDB 高風險操作)
gdb -p -ex "call close()" -ex detach -ex quit
umount /mnt/data
# umount: /mnt/data: target is busy
lsof +D /mnt/data
# 找出佔用進程 -> 停止服務/殺進程 -> 再次 umount
# 進程實際加載的庫版本
lsof -p 1234 | grep mem | grep '\.so'
# 檢查是否加載了預期之外的庫路徑
lsof -p 1234 | awk '/mem.*\.so/ {print $9}' | sort -u
# 前提: 進程仍在運行且持有文件 FD
lsof +L1 | grep deleted
# 例輸出: myapp 1234 user 4u REG 8,2 1024 12345 /tmp/important.log (deleted)
# 通過 /proc 恢復:
cp /proc/1234/fd/4 /tmp/recovered_important.log
# 宿主機上直接 lsof 可見容器進程 (需 root)
lsof -p <容器進程在宿主機的PID>
# 結合 nsenter 進入容器網絡命名空間
nsenter -t <宿主機PID> -n lsof -i
# 自定義輸出格式 (便於解析)
lsof -F pcn -i :80
# p=PID, c=COMMAND, n=NAME (每行一字段, 以字母開頭)
# JSON 輸出 (需 lsof 4.93+)
lsof -J -i :80
# 統計各進程連接數
lsof -i -n -P | awk 'NR>1 {print $1,$2}' | sort | uniq -c | sort -rn

| 工具 | 優勢 | 劣勢 | 適用場景 |
|---|---|---|---|
lsof | 功能最全、輸出豐富、支援所有文件類型、腳本友好 | 遍歷 /proc 較慢、非預裝需安裝 | 深度診斷、腳本自動化、綜合排查 |
ss | 內核級 Netlink 接口、極快、支援過濾表達式、預裝 | 僅網絡連接、無普通文件信息 | 高頻端口/連接統計、大規模併發監控 |
netstat | 傳統熟悉 | 已棄用、慢、輸出難解析 | 舊腳本兼容 |
fuser | 簡單查誰佔用文件/端口、可直接殺進程 | 信息少、無網絡狀態詳情 | 快速佔用定位、一鍵釋放 |
/proc/PID/fd | 零依賴、實時、可直接操作 FD | 需已知 PID、手動解析 | 極簡環境、容器調試、FD 級操作 |
lsof 是 Linux 系統可觀測性的基石之一。熟練掌握 lsof -i 網絡過濾、+L1 幽靈文件發現、-F 格式化輸出、/proc/PID/fd 文件恢復等核心技巧,能解決 90% 以上的「佔用、洩漏、掛載、恢復」類疑難雜症。將常用組合封裝為別名/函數/腳本庫(如 `port() { lsof -i -n -P | grep :$1; }`),融入日常運維肌肉記憶。