Linux 怎么查文件被谁占用?lsof 全场景
答案:lsof <文件> 直接看谁打开了它;lsof +D <目录> 递归查目录;lsof -p <PID> 反查进程打开了哪些 fd。因为 Linux 一切皆文件,套接字、管道、设备都能用 lsof 查。
一、文件 / 目录被谁占用
lsof /var/log/app.log # 谁打开了这个文件
lsof +D /var/log # 递归列出占用该目录下文件的进程
lsof +d /var/log # 只看目录本身这一层(非递归,更快)
fuser -v /data/file # 另一个工具:直接报 PID/用户/访问类型输出列含义:COMMAND 进程名、PID、USER、FD(文件描述符与模式)、TYPE、SIZE/OFF、NODE(inode)、NAME。
| FD 常见值 | 含义 |
|---|---|
cwd | 进程的当前工作目录 |
rtd | 根目录 |
1w/2w | 标准输出/错误,写模式 |
3u | 3 号 fd,读写模式(u=read&write) |
cwd很关键:即使没打开文件,只要某进程的工作目录在挂载点内,umount就会 busy,lsof +D能把这种进程也找出来。
二、反查进程打开了什么
lsof -p 12345 # 该进程所有打开的文件/套接字/管道
lsof -p 12345 -a -i # 该进程仅网络连接(-a 表示条件取交集)
ls -l /proc/12345/fd # 不装 lsof 时的原生替代:直接看 fd 软链
readlink /proc/12345/fd/3排查"文件删了但空间没释放""配置改了进程没生效(还持有旧 fd)""库升级后旧进程仍在用旧版本"都从
lsof -p或/proc/PID/fd入手。
三、网络:套接字也是文件
lsof -i :8080 # 谁占着 8080
lsof -iTCP -sTCP:LISTEN -P -n # 所有 TCP 监听
lsof -i -a -u nginx # nginx 用户的所有网络连接
-P不把端口转服务名、-n不反解主机名,输出更快更准。端口占用的完整排查见端口占用 FAQ,命令细节见 lsof 命令。
四、已删除但占空间:deleted
lsof +L1 | grep deleted
# java 1234 root 5w REG 8,1 5000000000 12345 /data/app.log (deleted)这是磁盘满但 du 对不上的根因:
rm删除目录项后,只要进程仍持有 fd,inode/数据块不释放,lsof 显示(deleted)且 SIZE/OFF 还在涨。处理:重启持有进程;不便重启时可截断其 fd(truncate -s0 /proc/1234/fd/5)让空间立刻回收。
五、umount target is busy
lsof +D /mnt/data # 列出在挂载点内的文件/工作目录
fuser -mv /mnt/data # 交互式查看占用者
fuser -km /mnt/data # 确认可杀后再用:直接杀掉占用者(谨慎)更安全的卸载可用
umount -l(lazy,先从命名空间摘除,等句柄关闭再真正卸载)或umount -R递归,但生产上应先用 lsof/fuser 弄清是什么进程在用(数据盘可能是数据库进程)。
FAQ
Q: 文件被谁占用? A: lsof /path/file 给出进程与 fd;目录用 lsof +D(递归)或 fuser -v。
Q: 看某进程打开了什么? A: lsof -p PID,或原生 ls -l /proc/PID/fd;只看网络加 -a -i。
Q: umount busy? A: lsof +D 挂载点/fuser -mv 找占用进程(含 cwd),处理后再卸载。
Q: 删除后空间不释放? A: 进程还持有句柄,lsof +L1 | grep deleted 定位,重启或截断 /proc/PID/fd/n。
Q: lsof 怎么查端口? A: 套接字即文件,lsof -i :端口,加 -P -n 更快;见端口占用 FAQ。
一句话总结:查文件占用用 lsof 文件、目录用 lsof +D、进程打开了什么用 lsof -p(或看 /proc/PID/fd);(deleted) 行对应删而未释放的磁盘空间,umount busy 用 lsof/fuser 找占用者;网络套接字也能 lsof -i 查。