【问题标题】:UNIX atomically swap or replace directories?UNIX 原子地交换或替换目录?
【发布时间】:2021-05-26 18:23:09
【问题描述】:

我有以下问题。我有两个目录,分别称为 dir1 和 dir2。它们都填充有文件和子目录。它们都在同一个文件系统上。 dir1 的内容是旧的,必须用 dir2 的内容替换。 dir1 的内容可以丢弃。但是,我需要这种替换以原子方式发生。我目前的解决方案如下。

mv dir1 dir1_backup; mv dir2 dir1; rm -rf dir1_backup

如果第一个命令失败,第二个命令将不会运行。这很好。但是,如果第二个命令失败怎么办? dir1 不再存在,我处于无效状态。

实现这一目标的最佳方法是什么?有可能吗?

【问题讨论】:

  • 可能为时已晚 - 进行原子目录交换的简单方法是通过符号链接。
  • 你不是说&& 而不是; 来分隔你的cmd吗?不幸的是,虽然&& 应该可以工作,但我不确定我是否愿意像那样“打赌商店”。我会构建一些进行验证的东西,尤其是在最后的rm 步骤之前。祝你好运。
  • 我见过 - stackoverflow.com/questions/307437/… - 以前。其中提出的解决方案失败了我的边缘案例。
  • 想解释一下为什么使用符号链接和mv -T point_to_dir2 point_to_dir1 在你的边缘情况下不起作用。

标签: unix directory move atomic swap


【解决方案1】:

Linux 提供renameat2 系统调用,带有RENAME_EXCHANGE 标志的系统调用将交换2 个对象:

renameat2(AT_FDCWD, "dir1", AT_FDCWD, "dir2", RENAME_EXCHANGE);

【讨论】:

【解决方案2】:

我不认为如果第一个失败是真的,你上面关于第二个命令将失败的断言是正确的。如果mv dir1 dir1_backup 失败,那么 dir1 仍然存在,mv dir2 dir1 将使 dir2 成为 dir1 的子目录。此外,由于您在第三个命令中将-f 传递给rm,因此删除不存在的目录将静默失败。

作为参考,三个 bash 运算符(假设这里是 bash)以及它们的作用:

  • ;只需在第一次退出后执行以下命令,无论退出状态如何。
  • && 仅当前一个命令完全退出(即退出状态为 0)时才执行以下命令。
  • ||仅当前一个命令不干净地退出(即,退出代码非零)时,才执行以下命令。

如果您希望每个命令的执行依赖于前一个命令的成功执行,那么您可能需要考虑以下内容:

    mv dir1 dir1_backup && mv dir2 dir1 && rm -rf dir1_backup

如果移动目录是您预期的失败模式,那么在继续删除旧目录内容之前测试移动的返回值或测试预期目录的存在可能是合理的。如果测试失败,则将旧目录内容移回。整体操作将失败,但至少您不会处于无效状态。例如:

    mv dir1 dir1_backup && \
    mv dir2 dir1 && \
    rm -rf dir1_backup || mv dir1_backup dir1

由于我们知道&&只有在前一个命令成功退出的情况下才会执行下面的命令,所以mv dir2 dir1只有在mv dir1 dir1_backup成功的情况下才会执行。

此外,rm -rf dir1_backup 只会在 dir2 到 dir1 的移动成功时执行。但是,如果最后一个退出代码(如果失败则由 mv dir2 dir1 返回的代码)非零,则 || 运算符会导致 mv dir1_backup dir1 执行。

希望对您有所帮助!让我知道是否需要澄清。

【讨论】:

  • cfunk,感谢您澄清这一点。我以为 ;和 && 做了与他们实际做的相反的事情。您的解决方案更接近我想要的,但有一个极端情况。第一个命令成功完成。第二个命令失败,触发最后一个命令。 (mv dir1_backup dir1) 想象一下如果 LAST 命令失败。我仍然处于无效状态:dir1 不存在。
  • 如果您能够在第一种情况下重命名目录,您希望阻止您将其移回的故障模式是什么?如果这是预期的,您可能需要调查符号链接的使用,而不是移动目录。如果可能,最好让访问目录的应用程序查看新位置,而根本不用担心打乱目录。
【解决方案3】:

在 Linux 上,您也许可以在旧目录之上绑定挂载新目录。但是,对于在旧目录中的目录(例如,它们当前的工作目录)上具有打开句柄的进程,您仍然会遇到问题。

mount --bind dir2 dir1

类似的技巧可以让您访问旧目录以进行清理。

如果此文件系统是通过 NFS 导出的,那么您可能需要确保将导出选项设置为允许穿越文件系统边界并在服务器上进行绑定挂载。

其他 *nix 也有类似的功能,但没有标准化。

【讨论】:

    猜你喜欢
    • 2012-02-13
    • 2023-03-08
    • 2010-12-23
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多