如何使用 lsof Linux (附實際例子)

有沒有想過如何找出系統上當前打開和正在使用的文件? 他 Linux lsof 命令列出打開的文件並提供大量附加信息。 通過這些實際示例了解如何使用 lsof。

lsof是什麼?

在任何本地可用 Linux 操作系統, lsof 該命令提供打開文件的列表。 但是,輸出可能有點神秘且較長,特別是當在給定係統上使用許多應用程序時。 讓我們看一下基礎知識。 lsof 生產。 我們將跑步 lsof 作為根。

要以 root 身份登錄,您可以打開終端窗口並鍵入如下命令 sudo susu 接收 root 身份驗證提示。 或者你可以運行 sudo lsof。 請注意,雖然您可以運行 lsof 作為普通的非 root 用戶,輸出可能不完整。

示例:基本 lsof 輸出

sudo su
lsof | head -n10

這裡我們使用以下命令啟動 lsof 工具 lsof 命令,並使用管道捕獲輸出的前十行(|)發送信息輸出 lsof 到高中 head -n10 僅捕獲前十(頭)行的命令。

lsof 該命令列出多列。 我們首先看到 COMMAND 列,其中列出了包含打開文件/打開文件鎖的二進製文件。 接下來我們看到 PID 進程 ID 列,該列在嘗試調試各種應用程序問題(包括不正確地持有文件鎖)時非常有用。 在下一節中,我們將討論 example 我們如何使用 lsof 結合 kill (破壞性地)終止包含錯誤文件鎖的應用程序。

如果您的操作系統支持,TID 列可以幫助您確定給定的行是進程還是任務。 如果輸出為空,如我們的中所示 example (它正在運行 Linux Mint,一個支持TID列輸出的操作系統),給定的行/命令是一個進程,而不是一個任務。 例如,如果您在操作系統上啟動計算器應用程序(即任務),則此列將填充任務/線程 ID 號。

TASKCMD 列包含任務命令的名稱。 同樣,僅當給定的行是任務而不是進程時,它才可見。 這通常與 COMMAND 第一列中顯示的命令/過程相同,但是,對於 example, Linux 允許任務更改其命令名稱,因此它可以包含有關該任務的附加信息。 USER 列列出了啟動進程/任務的用戶。

接下來,我們有一個重要的 FD(文件描述符)列,它可以列出文件描述符編號或指示文件描述符類型的特定文本字符串。 例如,如果您看到 cwd 在此列中,代表當前工作目錄,並指示給定進程或任務在當前工作目錄中具有打開的鎖,並且該工作目錄出現在 NAME 列中。

有關所有可能的完整列表 FD 鏈條類型 man lsof 在命令提示符下鍵入 / FD (斜線後、FD 前有 3 個空格)進入手冊後,按 ENTER 鍵查找 FD 部分。

在處理常規文件時,您可以將 FD 列視為計數器或唯一 ID 計數器,從 0 開始並增加到系統上常規打開文件的總數,最大打開文件數由設置 ulimit 定義-n 等

當查看常規文件時,FD 列將用於 example 展示 102u13w。 這兩個示例分別代表系統上第 102 個打開的文件,處於混合讀/寫訪問模式,如下所示 u flag/label 和第 13 個文件在系統上僅以寫訪問模式打開。

TYPE 列是不言自明的; 指示是否持有常規文件或目錄打開鎖。 這裡可能會顯示其他幾個標籤,並且搜索 / TYPEman lsof (如上所述)將提供完整的列表。

DEVICE 列通常列出大多數文件類型的設備編號,以逗號分隔。 他 SIZE/OFF 該列是文件大小,或以字節為單位的文件偏移量,NODE 列通常顯示本地文件的文件節點號或 NFS 文件 inode 號。 您還可以列出 example TCP 或 UDP(當提供的鎖是開放的 Internet 連接時)。

示例:將 lsof 與 Kill 結合使用

使用 lsof 結合 grep, awk y kill 人們可以在給定係統中搜索特定文件,然後終止該進程(使用如上所述的 PID 或進程標識符)。

請注意,只有在有意義的情況下才應該這樣做。 為了 example,您可能有一個多線程 Bash 腳本,它啟動許多不同的子 shell,其中每個子 shell 都掛起一個給定的文件,並等待其中一個線程掛起。 您知道阻塞進程的打開文件名,但不知道該進程/任務的 PID 是什麼。

在這種情況下,我們可以運行以下命令:

sudo su
lsof | grep 'some_file_descriptor' | awk '{print $2}' | xargs -I{} kill -9 {}

讓我們將其付諸實踐 example。 假設我們創建了以下腳本 test.sh/tmp:

rm -Rf workspace
mkdir workspace
cd workspace
sleep 36000

該腳本執行時將創建一個名為的目錄 workspace更改其上的目錄 cd 進而 sleep 10小時。 雖然乍一看這可能不會打開任何文件,但請記住 cwd 之前討論過; 該腳本有一個正在使用的當前工作目錄,即 /tmp/workspace

讓我們看看這在實踐中是如何運作的。 首先,我們定義(使用您最喜歡的文本編輯器,例如 vi),然後在終端會話中啟動腳本:

然後我們跳到輔助/新終端會話並運行 lsof尋找腳本的工作目錄,即 workspace:

lsof 與 grep 匹配文本是查找 lsof 詳細輸出的好方法

正如我們所看到的, lsof 不僅能夠找到我們的測試腳本 test.sh 你拿著一個 cwd 伴侶 /tmp/workspace但我們也看到 sleep從腳本內部開始,你拿著一個 cwd 在同一目錄中打開文件描述符(或更好的目錄)。

我們還可以看到 PID test.sh 腳本,以及 sleep 領域。 假設我們的 test.sh 腳本掛起,我們想徹底破壞性地殺死它,即 kill -9 這是在沒有任何正常關閉級別的情況下終止進程的最具破壞性的方法,並且這是基於腳本包含的打開文件(或在我們的例子中,打開目錄)。 我們從輔助終端發出以下命令:

lsof | grep "workspace" | awk '{print $2}' | xargs -I{} kill -9 {}

基於使用 grep 的 lsof 搜索,使用kill -9 終止進程

該命令將獲取先前的輸出並進一步解析它。 他 awk '{print $2}' 它基本上從第二列(進程 ID)和 xargs 命令將把第二列傳遞給 kill -9 (他 {} 命令中的內容將被任何輸入替換 xargs 收到)。

我們也可以預見到 lsof 有一個標題行包含 PID 而這段文字也將被傳殺。 雖然它不會產生問題,但更好的通用命令應該是 lsof | grep "workspace" | grep -v "PID" | awk '{print $2}' | xargs -I{} kill -9 {}或其他方式來完全過濾第一行。

我們的第一個/主要終端會話的結果是我們的腳本立即被終止:

test.sh 腳本刪除了在另一個終端中執行刪除的結果的輸出

如果您想了解有關 xargs 的更多信息,您可以閱讀結合使用 xargs bash -c 創建複雜命令。 有關 Bash 多線程編程,請參閱如何在 Bash 腳本中使用多線程處理。

結尾

在本文中,我們探討了使用 lsof、列出打開文件命令,以及每列在其默認輸出中代表什麼信息。 我們還研究了一個實際用例,其中我們使用 lsof 結合 grep, awk y kill 查找由腳本保持打開狀態的特定文件(或者在我們的例子中為目錄),然後結束該腳本,從而關閉打開的目錄。

如果您喜歡閱讀本文,請看一下我們的斷言、錯誤和崩潰:有什麼區別? 文章。