Linux 下檔案被 rm 刪除後,若仍有進程持有該檔案的開啟描述符,檔案實體資料仍駐留磁碟,可透過 /proc/PID/fd/ 回救。此技巧對日誌檔、資料庫事務日誌等持續寫入檔案極其有效。本文以 /var/log/messages 為例演示完整恢復流程。
/proc/PID/fd/N 是指向該描述符的符號連結,讀取即可獲取檔案內容。# 確認 syslogd 正在寫入
# lsof | grep /var/log/messages
syslogd 14572 root 1w REG 253,0 5584 1737237 /var/log/messages
# 誤刪除
# rm -f /var/log/messages
# 再次查看,標記為 (deleted)
# lsof | grep /var/log/messages
syslogd 14572 root 1w REG 253,0 5584 1737237 /var/log/messages (deleted)
從輸出可見:
14572(syslogd)1(標準輸出)/proc/14572/fd/1# 查看最後 10 行確認內容
# tail -n 10 /proc/14572/fd/1
Feb 4 20:02:25 host191 kernel: klogd 1.4.1, log source = /proc/kmsg started.
Feb 4 20:02:45 host191 root: aaa
...
# 完整恢復到原路徑
# cat /proc/14572/fd/1 > /var/log/messages
# ls -l /var/log/messages
-rw-r--r-- 1 root root 5584 Feb 4 20:17 /var/log/messages
# tail /var/log/messages # 內容完整
| 適用 | 不適用 |
|---|---|
| 日誌檔(持續寫入) | 靜態檔案刪除後無進程開啟 |
| 資料庫事務日誌 (redo/undo log) | 進程已退出/重啟 |
| 管道/Socket 暫存資料 | 檔案系統支援 undelete (ext4 搭配 extundelete) |
#!/bin/bash
# 掃描所有標記 (deleted) 的開啟檔案並嘗試恢復
lsof +L1 | grep deleted | while read line; do
pid=$(echo $line | awk '{print $2}')
fd=$(echo $line | awk '{print $4}' | sed 's/[^0-9]//g')
path=$(echo $line | awk '{print $9}')
if [ -e "/proc/$pid/fd/$fd" ]; then
cp "/proc/$pid/fd/$fd" "$path.recovered"
echo "Recovered $path -> $path.recovered"
fi
done
誤刪不慌,只要進程還在,/proc 就是你的時光機。
