以下脚本有时给我类似的东西can't remove a/b as it's not empty
ssh -T user@host <<EOF
cd somewhere
rm -rf a/b
EOF
但我登录到服务器并执行rm -rf a/b
然后我从来没有遇到过问题。
还有其他进程正在生成文件a/b
,这是否相关?
无论如何,如何制作一个脚本来确保“a/b”被删除?
答案1
还有其他进程正在向 a/b 生成文件,这是否相关?
很有可能。可能是rm -rf
先删除所有文件,然后删除所有目录。在幕后,rmdir
如果目录不为空,则删除目录的系统调用将失败。您可能会遇到竞争条件,其中rm -rf
检查目录是否为空,并且确实如此;然后另一个进程创建一个新文件; finallyrm -rf
调用rmdir
,但另一个进程预先创建了一个文件。
Faheem 的建议很好:将 anls
放入您的错误条件中
ssh -T user@host <<EOF
cd somewhere
rm -rf a/b || ( ls -a a/b && exit 1 )
EOF
答案2
rmdir(2)
如果目录不为空将会失败。如果另一个进程在rm(1)
删除文件时正在创建文件,它将不知道删除它们,因此当尝试rm(1)
删除它认为应该是空目录的内容时,它将失败并出现您发布的错误。
在目录中并发创建文件时删除目录的一种方法是重命名它:
mv a a~
rm -rf a~
a/b
如果创建文件的进程不是通过路径(open(2)
而不是openat(2)
)执行的,那么这可能不起作用。
我假设在其中创建文件的进程a/b
将重新创建该目录(如果该目录不存在),或者如果该目录不存在则将优雅地处理失败。由于您已经尝试从其他进程下删除该目录,这似乎是一个安全的假设。
答案3
如果竞争条件非常高:下一个命令将删除过时的文件,然后删除空目录:
find /somedir -type f -atime +3 -print0 | xargs -0 --no-run-if-empty rm -f; find /somedir -mindepth 1 -type d -empty -not -name "*.empty" -print0 | xargs -0 --no-run-if-empty -I{} mv {} {}.empty; sleep 30; find /somedir -type d -name '*.empty' -print0 | xargs -0 --no-run-if-empty rm -rf
或者一步一步:
find /somedir -type f -atime +3 -print0 | xargs -0 --no-run-if-empty rm -f;
find /somedir -mindepth 1 -type d -empty -not -name "*.empty" -print0 | xargs -0 --no-run-if-empty -I{} mv {} {}.empty;
sleep 30;
find /somedir -type d -name '*.empty' -print0 | xargs -0 --no-run-if-empty rm -rf;
睡30对于所有进程来说,完成写入删除目录是必需的。
警告:您可能会丢失新数据(就我而言,它是缓存,所以我不在乎)。