面向 Mac 用户的 lsof 命令详解

掌握 lsof 命令,找出 Mac 上哪些进程打开着文件。一份面向开发者和高级用户的指南。

你的外置驱动器推不出来。macOS 给你那条令人抓狂、含糊其辞的消息,说“可能有一个或多个程序正在使用它”。哪些程序?它不肯说。这正是 lsof 派上用场的地方。

这个名字代表“列出打开的文件”(list open files),而它做的正是这件事。在像 macOS 这样基于 Unix 的系统上,几乎一切都被当作文件,包括网络连接、设备和磁盘宗卷。当你无法推出一个驱动器时,lsof 会精确地告诉你是哪个进程在扣押它。

基本语法

在推出问题上使用 lsof 最简单的方式是:

lsof /Volumes/YourDriveName

将“YourDriveName”替换为驱动器的实际名称。如果名称含有空格,就用引号把整个路径括起来:

lsof "/Volumes/My Backup Drive"

这会返回一份列表,列出每一个在该宗卷上持有打开文件句柄的进程。每一行显示进程名称、它的 ID(PID)、运行它的用户,以及正被访问的具体文件的相关信息。

读懂输出

一份典型的 lsof 输出看起来大致是这样的:

COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mds_store  1234   root   4r   REG   1,12   524288  ...  /Volumes/External/.Spotlight-V100/...
Finder     5678   you    3r   DIR   1,12     1024  ...  /Volumes/External

最重要的几列是 COMMAND(进程名称)、PID(你用来终止它的进程 ID),以及 NAME(正被访问的实际文件路径)。

FD 列显示文件是如何被使用的。一个数字后面跟着“r”表示读取访问,“w”表示写入,“u”表示读写皆有。如果你看到“cwd”,说明该进程把那个位置作为它的当前工作目录。当你有一个 Terminal 窗口打开在驱动器上的某个文件夹时,就会发生这种情况。

找出是什么在阻止你的驱动器

具体到推出问题,你通常只需知道出现了哪些进程名称。常见的肇事者包括 mdsmds_stores(聚焦索引)、FinderQuickLookUIService(缩略图生成)和 fsevents(文件系统监视器)。

如果你看到大量输出、想缩小范围,你可以使用 grep:

lsof /Volumes/YourDriveName | grep -v "^COMMAND"

这会移除标题行,让你只看到实际的进程。如果你只想要唯一的进程名称:

lsof /Volumes/YourDriveName | awk '{print $1}' | sort -u

有用的标志

-c 标志按命令名称筛选。如果你怀疑聚焦是问题所在:

lsof -c mds /Volumes/YourDriveName

这只显示名称以“mds”开头的进程。

+D 标志会递归地列出一个目录中所有打开的文件:

lsof +D /Volumes/YourDriveName

这比基本语法更彻底,但在含有大量文件的大容量驱动器上可能会很慢。

要查看某个特定用户在驱动器上打开了哪些进程:

lsof -u yourusername /Volumes/YourDriveName

不用 sudo 使用 lsof

默认情况下,lsof 只显示你的用户账户所拥有的进程。由 root 运行的系统进程(如聚焦的 mds)不会出现,除非你用 sudo 运行 lsof:

sudo lsof /Volumes/YourDriveName

你需要输入你的密码。对于排查推出问题,使用 sudo 几乎总是必要的,因为系统进程常常正是那些阻止者。

终止阻止进程

一旦你从 lsof 输出中知道了进程 ID(PID),你就可以终止它:

kill 1234

将 1234 替换为实际的 PID。如果那不奏效,你可以强制它:

kill -9 1234

对此要小心。终止像 mds 这样的系统进程可能引发暂时的问题。该进程通常会自动重启,但你可能会看到聚焦在一分钟内表现古怪。终止像 Finder 这样的应用程序通常是安全的;macOS 会自动重启 Finder。

对于你自己拥有的应用程序(比如一个 shell 停留在驱动器目录中的 Terminal 窗口),更干净的做法是干脆正常关闭该应用程序,或在尝试推出之前先离开该驱动器。

常见情形

当前目录位于驱动器上的 Terminal:如果你 cd 进了你外置驱动器上的某个文件夹,那个 shell 进程就会占用着驱动器。要么 cd 到别处(cd ~),要么关闭那个 Terminal 窗口。

访达窗口:如果访达有一个窗口打开在驱动器上,甚至只是在边栏中选中了该驱动器,它都可能阻止推出。关闭任何显示着驱动器内容的访达窗口。

聚焦索引mdsmds_storesmdworker 进程会自动为新驱动器编制索引。你可以等它们完成、用 sudo mdutil -i off /Volumes/YourDriveName 禁用索引,或直接终止它们。

打开着文件的后台 App:一些应用程序即便在你关闭了文稿之后,仍会引用着最近的文件。像 Photoshop 这样的创意类应用程序或视频剪辑软件是常见的肇事者。彻底退出该 App 通常会释放那些文件。

超越命令行

如果你对 Terminal 不太自在,又不想每次需要拔掉驱动器时都去琢磨 lsof 的输出,那还有图形化的选项。

活动监视器可以显示某个特定进程打开的文件,但你得事先知道要检查哪个进程。它无法轻松回答“是什么在使用这个驱动器?”。

Ejecta 正是为这个问题而打造的。它显示你已连接的驱动器,辨认出是哪些进程在阻止每一个驱动器,并让你一键退出那些进程。它本质上把 lsof 所需的那番侦查工作做成了图形界面,还能帮你安全地处理系统进程。

命令行对偏好它的人来说很强大,但对于拔掉驱动器这样简单的事,它不该是必需的。

如果你不想每次都动用终端,Ejecta 会准确告诉你是哪个进程在占用硬盘——只需在菜单栏中点击一下即可退出它。

立即购买 — $9.99