我想运行一个删除.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
再次遍历树。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
似乎已经收到了一条错误消息:另一个区别是
-exec rm -f -- {} +
仅使用标准工具,而-delete
不是标准工具,即使有些普遍支持。例如 FreeBSD 和 GNU 支持它,但 Busybox 不支持。请参阅:查找:“-exec rm {};” 与“-delete”相比——为什么前者被广泛推荐?在 superuser.com 上。