如何使用 Linux lsof 命令

在 Linux 系統中,如果說一切皆為文件,那必然不僅僅指硬碟上的檔案。 本教程將引導你如何運用 lsof 命令,檢視所有被視為檔案處理的裝置與程序。

Linux 系統:萬物皆檔案

關於 Linux 系統中「一切皆為檔案」的說法,確實是準確的。 檔案本質上是位元組的集合。 當這些位元組被讀入程序或傳送至印表機時,它們會形成一個位元組流。 而當它們被寫入時,則會接收一個位元組流。

許多其他的系統組件,如鍵盤、網路連接、印表機和通訊程序,也都接收或產生位元組流。 正因如此,這些裝置在底層可以被視為檔案來處理,不論它們是接收、產生,或同時接收與產生位元組流。

這種設計理念簡化了 Unix 作業系統的實現。 它使我們可以使用一套精簡的處理程式、工具和應用程式介面 (API) 來管理各種不同的資源。

儲存在硬碟上的資料和程序檔案,是典型的檔案系統檔案。 我們可以使用 ls 命令列出它們,並獲取一些相關資訊。

但要如何找出所有其他被視為檔案的程序和裝置呢? 這時我們需要使用 lsof 命令。 這個命令會列出系統中所有開啟的檔案,也就是所有被當作檔案來處理的內容。

lsof 命令詳解

lsof 可以報告的許多程序或裝置屬於 root 或由 root 啟動,因此在使用 lsof 時,你需要搭配 sudo 命令來執行。

此外,由於輸出列表會相當長,我們將使用 less 命令來進行分頁檢視。

sudo lsof | less

lsof 的輸出結果出現之前,GNOME 使用者可能會在終端機視窗中看到一則警告訊息。

lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.

lsof 會嘗試處理所有已掛載的檔案系統。 出現這個警告訊息的原因是 lsof 遇到了 GNOME 虛擬檔案系統 (GVFS)。 這是一種特殊的 使用者空間檔案系統 (FUSE),作為 GNOME、其 API 和核心之間的橋梁。 除了掛載它的所有者(在此案例中為 GNOME)之外,沒有任何人(甚至 root 使用者)可以訪問這些檔案系統之一。 你可以忽略這個警告訊息。

lsof 的輸出結果非常詳盡。 最左邊的欄位包含:

最右邊的欄位包含:

lsof 欄位說明

並非所有的欄位都適用於每一種開啟的檔案類型。 有些欄位為空白是正常的。

命令 (COMMAND) 與開啟檔案的程序相關聯的命令名稱。
PID 開啟檔案的程序的程序識別碼。
TID 任務(執行緒)識別碼。 空白欄位表示它不是任務,而是一個程序。
使用者 (USER) 擁有此程序的用戶識別碼或名稱,或是擁有 /proc 目錄中相關資訊的用戶識別碼或登入名稱。
FD 顯示檔案的檔案描述符,詳情見下文。
類型 (TYPE) 與檔案相關聯的節點類型,詳情見下文。
裝置 (DEVICE) 包含裝置號碼,以逗號分隔,用於字元特殊、區塊特殊、常規、目錄或 NFS 檔案,或是用於識別檔案的核心引用位址。 它也可能顯示 Linux AX.25 套接字裝置的基底位址或裝置名稱。
大小/偏移 (SIZE/OFF) 顯示檔案的大小或檔案的偏移量(以位元組為單位)。
節點 (NODE) 顯示本地檔案的節點號碼,或伺服器主機中 NFS 檔案的 inode 號碼,或是 Internet 協議類型。 它可能會顯示串流的 STR 或 Linux AX.25 套接字裝置的 IRQ 或 inode 號碼。
名稱 (NAME) 顯示檔案所在的掛載點和檔案系統名稱。

FD 欄位詳解

在 FD 欄位中的檔案描述符可能有多種選項,詳細資訊請參考 手冊頁

FD 欄位項目可能由三部分組成:檔案描述符、模式字元和鎖定字元。 一些常見的檔案描述符如下:

  • cwd: 目前的工作目錄。
  • err: FD 資訊錯誤(請參考 NAME 欄位)。
  • ltx: 共用庫文本(程式碼和資料)。
  • m86: DOS 合併映射檔案。
  • mem: 記憶體映射檔案。
  • mmap: 記憶體映射裝置。
  • pd: 父目錄。
  • rtd: 根目錄。
  • txt: 程序文本(程式碼和資料)。
  • 一個數字,代表檔案描述符。

模式字元可以是以下之一:

  • r: 讀取權限。
  • w: 寫入權限。
  • u: 讀寫權限。
  • ' ':空白字元,表示模式未知且沒有鎖定字元。
  • -:模式未知且有鎖定字元。

鎖定字元可以是以下之一:

  • r: 部分檔案的讀取鎖。
  • R: 整個檔案的讀取鎖。
  • w: 部分檔案的寫入鎖。
  • W: 整個檔案的寫入鎖。
  • u: 任意長度的讀寫鎖。
  • U: 未知的鎖定類型。
  • ' ': 空白字元,表示沒有鎖定。

類型 (TYPE) 欄位詳解

類型欄位中可能出現的項目超過 70 個。 你可能會看到的一些常見條目如下:

  • REG: 常規檔案系統檔案。
  • DIR: 目錄。
  • FIFO: 先進先出。
  • CHR: 字元特殊檔案。
  • BLK: 區塊特殊檔案。
  • INET: 網際網路套接字。
  • unix: UNIX 域套接字。

檢視開啟檔案的程序

要查看哪些程序開啟了特定的檔案,只需將檔案名稱作為參數傳遞給 lsof。 例如,要查看哪些程序開啟了 kern.log 檔案,可以使用以下命令:

sudo lsof /var/log/kern.log

lsof 的輸出會顯示由使用者 syslog 啟動的單一程序 rsyslogd

檢視目錄中開啟的所有檔案

要查看目錄中開啟的所有檔案以及開啟它們的程序,請將目錄作為參數傳遞給 lsof。 你必須使用 +D(目錄)選項。

要查看 /var/log/ 目錄中開啟的所有檔案,請使用以下命令:

sudo lsof +D /var/log/

lsof 會回應該目錄中所有開啟檔案的列表。

要查看 /home 目錄中開啟的所有檔案,請使用以下命令:

sudo lsof +D /home

顯示 /home 目錄中開啟的檔案。 請注意,由於某些欄位的描述較短,整個列表會比較窄。

列出程序開啟的檔案

要查看特定程序開啟的檔案,請使用 -c(命令)選項。 請注意,你可以一次向 lsof 提供多個搜尋詞。

sudo lsof -c ssh -c init

lsof 會提供由命令列上提供的任一程序開啟的檔案列表。

檢視使用者開啟的檔案

若要將顯示結果限制為特定使用者開啟的檔案,請使用 -u(使用者)選項。 在此範例中,我們將查看由代表 Mary 擁有或啟動的程序所開啟的檔案。

sudo lsof -u mary

所有列出的檔案都是代表使用者 Mary 開啟的。 這包括由桌面環境開啟的檔案,或是僅僅是因為 Mary 登入而開啟的檔案。

排除使用者開啟的檔案

要排除使用者已開啟的檔案,請使用 ^ 運算子。 從列表中排除使用者可以更容易地找到你感興趣的資訊。 你必須像之前一樣使用 -u 選項,並在使用者名稱的開頭加上 ^ 字元。

sudo lsof +D /home -u ^mary

這次,/home 目錄的列表中不包含使用者 Mary 開啟的任何檔案。

列出程序開啟的檔案

要列出特定程序開啟的檔案,請使用 -p(程序)選項並提供程序識別碼作為參數。

sudo lsof -p 4610

你會看到由你提供的程序識別碼所開啟的所有檔案列表。

列出已開啟檔案的程序識別碼

要查看已開啟特定檔案的程序的程序識別碼,請使用 -t(簡潔)選項,並在命令列上提供檔案的名稱。

sudo lsof -t /usr/share/mime/mime.cache

程序識別碼會顯示在一個簡單的列表中。

使用 AND 和 OR 搜尋

讓我們列出使用者 Mary 開啟的與 SSH 程序相關的檔案。 我們知道可以在命令列上提供多個搜尋項目,所以這應該很容易。

sudo lsof -u mary -c ssh

現在讓我們看看 lsof 的輸出。 這看起來不對勁; 輸出中有由 root 啟動的項目。

這不是我們所期望的。 發生了什麼?

當你提供多個搜尋詞時,lsof 會返回與第一個搜尋詞或第二個搜尋詞匹配的任何檔案,依此類推。 換句話說,它執行 OR 搜尋。

若要使 lsof 執行 AND 搜尋,請使用 -a(和)選項。 這表示唯一會被列出的檔案,必須是與第一個搜尋詞和第二個搜尋詞匹配的檔案,依此類推。

讓我們再試一次並使用 -a 選項。

sudo lsof -u mary -c ssh -a

現在列表中每個檔案都是由 Mary 或代表 Mary 開啟的,並且與 SSH 命令相關聯。

自動刷新顯示

我們可以使用 +|-r (重複) 選項將 lsof 設為重複模式。 可以透過兩種方式應用重複選項,+r-r。 我們還必須加入我們希望 lsof 在刷新顯示之前等待的秒數。

使用任一種格式的重複選項,lsof 都會像往常一樣顯示結果,但它會在顯示的底部新增一條虛線。 它會等待命令列上提供的秒數,然後用一組新結果刷新顯示。

使用 -r 選項,這將會一直持續到你按下 Ctrl+C。 使用 +r 格式,它將會一直持續到沒有要顯示的結果,或是直到你按下 Ctrl+C。

sudo lsof -u mary -c ssh -a -r5

請注意列表底部的虛線。 這會在刷新輸出時分隔每個新的資料顯示。

顯示與網際網路連線相關的檔案

-i (網際網路) 選項可讓你查看與網路和網際網路連線相關的程序所開啟的檔案。

lsof -i

顯示透過網路和網際網路連線開啟的所有檔案。

按程序識別碼顯示與網際網路連線相關的檔案

若要查看與特定程序識別碼相關聯的網際網路連線所開啟的檔案,請加入 -p 選項和 -a 選項。

在這裡,我們正在尋找由網際網路或網路連線開啟的檔案,並由識別碼為 606 的程序所開啟。

sudo lsof -i -a -p 606

顯示由程序識別碼 606 開啟的,與網際網路或網路連線相關聯的所有檔案。

顯示與網際網路連線和命令相關的檔案

我們可以使用 -c(命令)選項來尋找特定程序開啟的檔案。 若要尋找已透過網際網路或與 ssh 程序相關聯的網路連線開啟的檔案,請使用以下命令:

lsof -i -a -c ssh

由於 ssh 程序開啟的所有檔案都會列在輸出中。

顯示與網際網路連線和端口相關的檔案

我們可以透過 lsof 報告透過網際網路或特定端口上的網路連線所開啟的檔案。 為此,我們使用 : 字元,後接端口號碼。

在這裡,我們要求 lsof 列出已透過網路或網際網路連線使用端口 22 開啟的檔案。

lsof -i :22

所有列出的檔案都是由與端口 22(這是 SSH 連線的預設端口)關聯的程序所開啟。

顯示與網際網路連線和協議相關的檔案

我們可以要求 lsof 顯示由使用特定協議的,與網路和網際網路連線相關的程序所開啟的檔案。 我們可以從 TCP、UDP 和 SMTP 中進行選擇。 讓我們使用 TCP 協議,看看我們得到了什麼。

sudo lsof -i tcp

唯一列出的檔案是使用 TCP 協議的程序所開啟的檔案。

我們僅觸及了表面

雖然這是 lsof 的一些常見使用案例,並為你提供一個良好的基礎,但除此之外還有許多知識值得探索。 從手冊頁超過 2,800 行的事實來看,你就可以判斷還有多少東西等待你挖掘。

lsof 命令可以用於深入挖掘開啟檔案和虛擬檔案的層次。 我們提供了一個概略的說明; 詳情請參閱 手冊頁