【问题标题】:Compare and sync two (huge) directories - consider only filenames比较和同步两个(巨大的)目录 - 只考虑文件名
【发布时间】:2021-09-09 15:41:06
【问题描述】:

我想在 Linux 中的两个目录之间进行单向同步。一个包含文件,另一个包含 已处理 个文件,但具有相同的目录结构和相同的文件名,但可能缺少某些文件。

现在我在做:

cd $SOURCE
find * -type f | while read fname; do
    if [ ! -e "$TARGET$fname" ]
    then
        # process the file and copy it to the target. Create directories if needed.
    fi
done

这可行,但速度非常慢。 有更好的方法吗?

大约有 50.000.000 个文件,分布在目录和子目录中。每个目录包含的文件/子目录不超过 255 个。

我看过

  • rsync: 似乎它总是进行大小或时间戳比较。这将导致每个文件都被标记为不同,因为处理需要一些时间并更改文件内容。

  • diff -qr: 无法弄清楚如何让它忽略文件大小和内容

编辑

有效假设:

  • 仅根据目录/文件名进行比较
  • 我们不关心文件元数据和/或属性(例如,大小、所有者、权限、上次修改的日期/时间等)
  • 我们不关心可能驻留在目标目录中但在源目录中没有匹配文件的文件。这只是部分正确,但从源中删除的情况很少见,而且是批量发生的,所以我会为此做一个特殊情况。

【问题讨论】:

  • fwiw,您可以使用comm -13 "${srcfiles}" "${tgtfiles}" 获取${TARGET}-only 文件的列表,用于批量删除过程;或者,将comm 调用替换为单个diff,并使用条件来确定结果是${SOURCE}-only 还是${TARGET}-only;就个人而言,我发现 comm 输出更容易使用,ymmv ...

标签: linux bash synchronization rsync


【解决方案1】:

假设:

  • 仅根据目录/文件名进行比较
  • 我们不关心文件元数据和/或属性(例如,大小、所有者、权限、上次修改的日期/时间等)
  • 我们不关心可能驻留在目标目录中但在源目录中没有匹配文件的文件

我看不出有什么办法可以比较大约 5000 万个条目的 2 个列表,但我们可以尝试消除 bash 循环解决方案的逐个条目方法...

一个想法:

# obtain sorted list of all $SOURCE files

srcfiles=$(mktemp)
cd "${SOURCE}"
find * -type f | sort > "${srcfiles}"

# obtain sorted list of all $TARGET files

tgtfiles=$(mktemp)
cd "${TARGET}"
find * -type f | sort > "${tgtfiles}"

# 'comm -23' => extract list of items that only exist in the first file - ${srcfiles}

missingfiles=$(mktemp)
comm -23 "${srcfiles}" "${tgtfiles}" > "${missingfiles}"

# process list of ${SOURCE}-only files

while read -r missingfile
do
    process_and_copy "${missingfile}"
done < "${missingsfiles}"

'rm' -rf "${srcfiles}" "${tgtfiles}" "${missingfiles}"

此解决方案本质上(仍然)是串行的,因此如果存在“大量”丢失文件,则处理所述丢失文件的总时间可能是可观的。

有了足够的系统资源(cpu、内存、磁盘吞吐量),“更快”的解决方案将着眼于并行化工作的方法,例如:

  • 在不同的$SOURCE/$TARGET 子目录上运行并行find/sort/comm/process 线程(如果丢失文件的数量均匀分布在不同的子目录中,可能会很好)或...
  • 坚持串行find/sort/comm 但split ${missingfiles} 成块,然后生成单独的操作系统进程到process_and_copy 不同的块

【讨论】:

  • 你的假设是正确的。 comm 是我的新手。我认为您的解决方案可能运作良好。
  • 我不会将文件名存储在临时文件中...改用进程替换。 comm -23 &lt;(find ...) &lt;(find ...)
  • @Shawn 最坏情况:2x 50 百万个文件名,比如每个目录/文件平均 50 个字符 ... 5GB ... 在较小的(内存)系统上可能会出现问题,不是吗?是的,需要确保 2x 文件最终的 FS 有 5GB 空间,但磁盘仍然比内存相对便宜(呃)
  • 首先,谢谢。有用。 @markp-fuso 关于文件大小的假设非常好。我对 1/5 的数据进行了测试,源的 tmp 文件为 1.1 GiB。虽然这适合 RAM,但我更喜欢一个文件,因为每个 find 步骤大约需要 20 分钟。现在查找文件不再是我需要优化处理的瓶颈。
  • @markp-fuso 现在已经足够快了。创建丢失文件列表需要不到一个小时。对于处理,我现在可以拆分缺失文件列表并并行启动多个任务,以便充分利用服务器。实际的处理算法由其他人完成。他们现在可以调查了。幸运的是,每个文件都可以独立处理。因此,他们要么对其进行优化,要么对其投入更多的 CPU 能力(=钱)。 ... 顺便提一句。 comm -23 "${srcfiles}" ${tgtfiles}" &gt; "${missingfiles}" 行中缺少一个“ - 我无法编辑它,因为“编辑需要 6 个字符”
猜你喜欢
  • 1970-01-01
  • 2023-04-07
  • 2012-12-31
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多