面向 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 窗口打开在驱动器上的某个文件夹时,就会发生这种情况。
找出是什么在阻止你的驱动器
具体到推出问题,你通常只需知道出现了哪些进程名称。常见的肇事者包括 mds 和 mds_stores(聚焦索引)、Finder、QuickLookUIService(缩略图生成)和 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 窗口。
访达窗口:如果访达有一个窗口打开在驱动器上,甚至只是在边栏中选中了该驱动器,它都可能阻止推出。关闭任何显示着驱动器内容的访达窗口。
聚焦索引:mds、mds_stores 和 mdworker 进程会自动为新驱动器编制索引。你可以等它们完成、用 sudo mdutil -i off /Volumes/YourDriveName 禁用索引,或直接终止它们。
打开着文件的后台 App:一些应用程序即便在你关闭了文稿之后,仍会引用着最近的文件。像 Photoshop 这样的创意类应用程序或视频剪辑软件是常见的肇事者。彻底退出该 App 通常会释放那些文件。
超越命令行
如果你对 Terminal 不太自在,又不想每次需要拔掉驱动器时都去琢磨 lsof 的输出,那还有图形化的选项。
活动监视器可以显示某个特定进程打开的文件,但你得事先知道要检查哪个进程。它无法轻松回答“是什么在使用这个驱动器?”。
Ejecta 正是为这个问题而打造的。它显示你已连接的驱动器,辨认出是哪些进程在阻止每一个驱动器,并让你一键退出那些进程。它本质上把 lsof 所需的那番侦查工作做成了图形界面,还能帮你安全地处理系统进程。
命令行对偏好它的人来说很强大,但对于拔掉驱动器这样简单的事,它不该是必需的。
如果你不想每次都动用终端,Ejecta 会准确告诉你是哪个进程在占用硬盘——只需在菜单栏中点击一下即可退出它。
立即购买 — $9.99