1. 程式人生 > >最暴力的 rm -rf 命令居然刪除目錄失敗了!為什麼?

最暴力的 rm -rf 命令居然刪除目錄失敗了!為什麼?

當我們在Linux系統中解除安裝軟體或清理資料時,經常會使用rm -rf命令去刪除某個目錄,例如刪除/tmp/tektea目錄:

[code lang=”shell”]# rm -rf /tm/tektea[/code]

rm命令的-r和-f這兩個引數的man含義如下:

-r, -R, –recursive
remove directories and their contents recursively

-f, –force
ignore nonexistent files, never prompt

所以-r和-f分別表示可遞迴刪除目錄和強制刪除檔案,組合起來就是我們在Linux系統中所熟知的、最暴力的強制刪除某個目錄的命令了,即便目錄下檔案正在被讀寫,也依然會幹乾淨淨的刪除掉該目錄,因為有-f引數,聽起來合情合理。但你現在已經看了本文的標題,你開始迷惑了吧?

沒關係,下面我們通過一些測試來驗證下這個暴力的 rm -rf 命令,看看它是不是真的那麼生猛,可以破壞一切目錄。

用例1:使用cp命令持續往/tmp/tektea目錄下拷貝檔案,然後rm -rf /tmp/tektea,測試程式碼如下

[code lang=”shell”]# cat test1.sh
#!/bin/bash

i=1
while true
do
cp /tmp/testfile /tmp/tektea/$i
let i++
done

# cat /tmp/testfile
hi[/code]

驗證結果:執行bash test1.sh後,rm -rf /tmp/tektea刪除成功

用例2:

使用dd命令持續往/tmp/tektea目錄下寫檔案,然後rm -rf /tmp/tektea,測試程式碼如下

[code lang=”shell”]# cat test2.sh
#!/bin/bash

while true
do
dd if=/dev/zero of=/tmp/tektea/ddfile bs=1024 count=1000000000
let i++
done[/code]

驗證結果:執行bash test2.sh後,rm -rf /tmp/tektea刪除成功

用例3:使用echo命令持續往/tmp/tektea目錄下的檔案寫資料,然後rm -rf /tmp/tektea,測試程式碼如下

[code lang=”shell”]# cat test3.sh
#!/bin/bash

while true
do
echo hi >>/tmp/tektea/echofile
done[/code]

驗證結果:執行bash test3.sh後,rm -rf /tmp/tektea刪除失敗,且有以下報錯:

# rm -rf /tmp/tektea/
rm: cannot remove `/tmp/tektea’: Directory not empty

通過上面的驗證,首先我們可以得出這條結論:使用rm -rf命令刪除目錄時,如果該目錄下的檔案正在被寫入,那麼會存在刪除失敗的可能

那麼,以上三個用例都是在往/tmp/tektea目錄寫入資料,為什麼僅僅是第三個場景會失敗呢?

各種跡象都把根因指向到了 rm 命令(有興趣的朋友可以下載Linux中rm命令的原始碼走讀下),rm命令在-r -f強制刪除目錄時,其邏輯是這樣的:

1)從被刪除目錄的最裡層遞迴刪除檔案;
2)當最裡層目錄A的檔案被刪除完以後,再刪除該層資料夾A;
3)在刪除資料夾A前,再檢查目錄A下是否還有檔案,如果有則報錯Directory not empty(編外:注意這裡了

現在再來回答這個問題——“為什麼僅僅是第三個場景會失敗呢?”,不過在回答前,我先給大家展示兩個資料:

1. 用例1使用cp往/tmp/tektea目錄拷貝資料,15秒大約生成了8600個檔案,每秒約573檔案,相當於每秒573次寫入
2. 用例3使用echo往/tmp/tektea/echofile寫資料,15秒大約在echofile中寫入了59萬行,每秒約40000次寫入

所以結合rm的實現和幾個用例差異可以清楚的知道——在刪除某個目錄時,若有程序往該目錄寫入資料,則需要先停止該程序的服務(或kill掉該程序),所以我們的一些Shell程式碼在解除安裝或刪除目錄時就存在失敗的可能。