仅当目录不是挂载点时才安全删除该目录

仅当目录不是挂载点时才安全删除该目录

不幸的是,我被迫使用一款软件,它对自动安装和卸载网络卷的处理非常糟糕;它有一个恼人的倾向,会留下安装点所在的目录,但在稍后再次安装该卷时无法正确处理这种情况(它是应该整理但经常不整理)。

当然,我会要求开发人员修复该问题,但与此同时,我需要自己做一些事情来整理安装点。

所以本质上我需要做的是删除该目录,但前提是它不是当前是一个安装点(因为我不想意外删除该卷的内容)。

现在,我可以轻松获取目录的设备 ID 并将其与 root 的设备 ID 进行比较,但是如果我使用这样的比较,则可能会出现竞争条件,即,如果在检查设备 ID 之间安装了卷并打电话rm -r /mnt/point

find还有其他选择吗?我对使用命令选项的可能性很感兴趣-xdev,但我不确定如何实际提供比较点,因为find /mnt/point -xdev目标和其内容是同一设备,所以不起作用。

另外,使用rmdir剩余文件夹始终为空的假设似乎不可靠,因为在某些系统上,安装点内部可能有一个文件;例如,macOS 会.autodiskmounted在其中保留一个文件。当我可以创建此类情况的列表并处理它们,如果可能的话,有一个更通用的解决方案供将来参考会很好(并且希望对其他人有用)。

答案1

如果该目录是挂载点,它将很忙,并且您不应该能够重命名它。

$ sudo mv /mnt /mnt.old
mv: cannot move '/mnt' to '/mnt.old': Device or resource busy

如果它只是一个常规目录,您应该能够重命名它。

$ sudo mv /mnt /mnt.old

如果移动成功,请重新创建挂载目录并删除重命名的目录。或者,您可以在删除之前验证重命名的目录是否是您期望的文件系统的一部分。

答案2

如果您使用的是 Linux

您可以使用以下命令测试目录是否是挂载点mountpoint

为了避免挂载点在 test 和 之间出现/消失rm -r,您需要在单独的目录中运行脚本挂载命名空间私有子树(挂载不会从/到新的命名空间传播)。这可以通过以下方式完成unshare

unshare -m --propagation private -- "<delete script>"

一切都在同一个脚本中:

#!/bin/sh

unshare -m --propagation private -- sh -e <<EOF

if ! mountpoint -q "<path>"; then
    rm -r "<path>"
fi

EOF

答案3

您不能rmdir使用非空目录或挂载点目录。所以这将满足您的要求:

rm -f mountpoint/.autodiskmounted    # MacOS cookie
rmdir mountpoint 2>/dev/null

如果您在脚本中运行出错时退出设置后,即可使用rmdir ... || true。 (请注意,这--ignore-fail-on-non-empty没什么用,因为在尝试删除挂载点时我们会收到未捕获的错误。)

我应该指出,我无法访问 Mac 系统,因此我无法测试文件.autodiskmounted系统真正安装时文件是否存在,或者文件系统卸载时它是否是占位符。

相关内容