明明 df -h 顯示分區 95% 滿載,du -sh /* 卻只加總到 60% —— 這 35% 去哪了?本文針對 Linux 磁碟空間「失蹤」的三大經典成因,提供定位指令、原理圖解與一鍵清理腳本。
# df 看分區用量
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 100G 90G 5G 95% /
# du 看目錄佔用(根目錄)
du -sh /* 2>/dev/null | sort -hr
# 總和僅 60G,少了 30G!
du -sh * 的 * 不會匹配以 . 開頭的隱藏項。常見場景:/root/.cache、/var/spool/mail/.*、/tmp/.ICE-unix、應用程式寫入的 ./.large_temp。
# 只統計隱藏項
du -sh .[^.]* 2>/dev/null | sort -hr
# 完整掃描(含隱藏)
du -sh /* .[^.]* 2>/dev/null | sort -hr
原目錄 /data 已有 20G 檔案,執行 mount /dev/sdb1 /data 後,原檔案被新檔案系統「遮蓋」,du 看不見,但 inode 仍佔用空間,df 仍計入。
# 找出所有掛載點
findmnt -rn -o TARGET,SOURCE,FSTYPE | while read mnt src fs; do
# 比較掛載前後 inode 數(需掛載前基線)
echo "=== $mnt ($src) ==="
ls -la "$mnt" | head -5
done
# 快速檢測:同一 inode 出現在多個掛載點
find / -xdev -printf '%i %p\n' 2>/dev/null | sort -k1,1n | uniq -D -w 10
umount /data # 解掛載
ls -la /data # 原檔案重現
mv /data/* /backup/ # 遷移資料
mount /dev/sdb1 /data # 重新掛載
mv /backup/* /data/ # 寫回新檔案系統
進程持續寫入 app.log,運維執行 > app.log 清空內容。因檔案描述符(fd)仍被進程持有,inode 不釋放,磁碟空間不歸還;ls -lh 顯示 0,du 統計 0,但 df 仍計佔用。
# 找出已刪除但仍被持有的檔案
lsof -nP | grep '(deleted)'
# 輸出範例
java 1234 user 10u REG 253,0 10G 12 /var/log/app.log (deleted)
# 釋放空間(不重啟進程)
: > /proc/1234/fd/10 # 透過 /proc 截斷 fd 指向的 inode
#!/bin/bash
# disk_lost.sh — 快速定位空間失蹤原因
echo "=== 1. 隱藏項佔用 ==="
du -sh /.[^.]* 2>/dev/null | awk '$1+0>100' | sort -hr
echo -e "\n=== 2. 掛載點遮蓋疑點 ==="
findmnt -rn -o TARGET | while read mnt; do
if [ -d "$mnt" ] && [ "$(ls -A "$mnt" 2>/dev/null | wc -l)" -gt 0 ]; then
echo "⚠ $mnt 非空,可能被遮蓋"
fi
done
echo -e "\n=== 3. 已刪除未釋放檔案 ==="
lsof -nP | awk '/\(deleted\)/{print $1,$2,$9,$10}' | sort -k4 -hr | head -20
mount --bind /empty /target && mount /dev/sdb1 /targetlogrotate + copytruncate 或 systemd-journald,避免 > file 產生稀疏檔df -i(inode 耗盡同樣導致無法寫入)結語: 空間失蹤 90% 以上屬於上述三類。下次遇到 df 與 du 對不上,先跑 lsof | grep deleted、再查隱藏項、最後核對掛載點,通常 5 分鐘內鎖定元兇。