“rm -rf a/b”说“a/b 不为空”的原因是什么?

“rm -rf a/b”说“a/b 不为空”的原因是什么?

以下脚本有时给我类似的东西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对于所有进程来说,完成写入删除目录是必需的。

警告:您可能会丢失新数据(就我而言,它是缓存,所以我不在乎)。

相关内容