刪除所有超過 7 天的文件的 Cron 作業:-exec rm -f {} ;vs-刪除
我想執行一個刪除
.txt
超過 7 天的文件的 cron 作業。我有兩個命令。第一個命令:/usr/bin/find /var/www/example.com/wp-content/targetdir -name "*.txt" -type f -mtime +7 -exec rm -f {} \;
第二條命令:
/usr/bin/find /var/www/example.com/wp-content/targetdir -name "*.txt" -type f -mtime +7 -delete
這兩個命令都可以用來刪除
.txt
超過 7 天的文件。我讀過第一個命令與race condition
. 能否詳細說明使用第二個命令相對於第一個命令的優勢?使用其中一個的優點和缺點是什麼?
我看到的比賽是這樣的,從Stéphane Chazelas 的評論到另一個問題:
請注意,
-exec rm {} +
有競爭條件漏洞-delete
(如果可用)沒有。所以不要在其他人可寫的目錄上使用它。一些發現還具有-execdir
減輕這些漏洞的作用。我實際上並沒有在(*)那裡看到詳細說明,但是我在那裡看到的比賽與如何將完整路徑傳遞給文件有關,從而導致在該過程中
-exec rm
再次遍歷樹。rm
在
find
遍歷樹並評估它在命令行上給出的條件之後,rm
再次遍歷樹,它不知道給定的條件find
,所以現在它們沒有被檢查。使用-delete
and-execdir
,find
遍歷樹,進行任何檢查,然後刪除文件,始終保持目錄上的文件描述符打開。
find
有人可能會介入並在評估其條件和rm
執行之間重命名文件或目錄。所以,像這樣:
- 根執行
find . -type f -user joe -exec rm -f {} \;
find
執行並找到目錄./this/
,其中包含使用者擁有的一些文件joe
- 另一個使用者重命名
./this
並創建一個具有相同名稱的符號連結,指向其他地方find
執行rm -f ./this/hello.txt
,現在跟隨符號連結。
hello.txt
現在可以由任何人擁有,而不僅僅是 userjoe
,並且因為find
是作為 啟動的root
,rm
所以它也很高興地刪除了符號連結另一端的文件。這是一個經典的使用時間檢查 (TOCTTOU) 漏洞。人們可能會提出更糟糕的例子,但這是一個普遍的想法。
使用
-delete
or ,這不會發生,因為打開-execdir
的文件描述符仍然指向同一個目錄,即使該目錄被重命名。將其工作目錄設置為該目錄執行(有系統呼叫通過文件描述符更改工作目錄,同樣不通過名稱查找),同時同樣刪除使用相對於包含目錄的名稱(使用)。find``./this``-execdir``rm``fchdir()``-delete``unlinkat()
請注意,預設情況下(即沒有
-L
選項),find
在遍歷目錄樹時不遵循找到的符號連結。這在這裡沒有幫助,因為再次rm
只是將它提供給底層系統呼叫的路徑傳遞給了底層系統呼叫,並且像往常一樣遵循符號連結。這確實意味著被替換的目錄(./this
上面)必須是一個被符號連結(或另一個目錄)替換的實際目錄,而不是被另一個符號連結替換的符號連結。(*)寫完這篇文章 20 分鐘後,我注意到 Stéphane 的回答(連結如下)確實有一個指向描述相同種族問題的 GNU 手冊的連結。(嘆。)
-delete
暗示-depth
和無效的問題與此-prune
無關,而不是競爭條件。為什麼 find with -delete 刪除了我的/save/ 目錄中的文件,而 find without delete 無法找到它們?GNU coreutilsfind
似乎已經收到了一條錯誤消息:$ find a -name foo -prune -o -name hello.txt -delete find: The -delete action automatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
另一個區別是
-exec rm -f -- {} +
僅使用標準工具,而-delete
不是標準工具,即使有些普遍支持。例如 FreeBSD 和 GNU 支持它,但 Busybox 不支持。請參閱:查找:“-exec rm {};” 與“-delete”相比——為什麼前者被廣泛推薦?在 superuser.com 上。