【问题标题】:Bash - replacing small range of lines in a huge text file efficientlyBash - 有效地替换大文本文件中的小范围行
【发布时间】:2016-05-17 16:45:27
【问题描述】:

我正在解决一个问题,我必须用另一个(更小但仍然很大)文本文件中的数据替换一个巨大文本文件中的特定范围的行。

假设 file1 有 10,000 行,file2 有 3,000 行。我需要执行以下类型的操作:从 file2 中提取第 901-970 行并将它们插入到 file1 的第 8701-8770 行中,替换之前的内容。在我正在处理的问题中,file1 有 6100 万行,而 file2 有 1800 万行。我需要有效地完成这个操作,因为它被执行了多次 - 最后 file2 的全部内容将在 file1 的某个地方。

到目前为止,我得到的最佳解决方案是将两个文件拆分为小文件,每个文件都有要复制和替换的块的行数(在上面的示例中为 70)。事实证明,这比头尾组合更有效地提取文件的某些部分,但它仍然需要触及 file1 中未修改的部分。

我想知道是否有 awk/grep/sed 解决方案。提取file2的一部分不是问题,但我不知道如何在不加载整个文件的情况下替换file1的一行。

谢谢!

【问题讨论】:

  • 您可以将文件分区不一定为偶数行。例如:File1_1 (1-900)、File1_2 (901_970)、File1_3 (971_) 和 File2 类似。然后加入这些部分。 File1_1、File2_1、File1_3 等。如果您的部分很大,则意味着部分数量可以管理。
  • 您应该明确您的字面意思是按行号进行处理,或者这只是向我们展示问题范围的近似值,但您确实希望扫描特定字符串以进行标记将发生替换的地方。祝你好运
  • @karafka 这也是一种可能性,但由于我需要在整个文件中进行多次替换,我仍然会有大量的部分。谢谢。
  • @shellter 我的数据只有数字,替换由行号确定,但由于每个数字都有相同的字节数,我设法解决了按字节而不是按字节标记部分的问题电话号码。谢谢。

标签: bash sed split


【解决方案1】:

问题是您必须执行随机访问类型的操作(与顺序处理不同)以“避免接触”file1 中不变的部分,并且文件的随机访问位于字符/字节级别,而不是行级别。也就是说,如果在 file1 中被替换的 bytes 的数量(而不是行)与来自 file2 的 bytes 的数量相同,您可以这样做(使用fseek 等)。但听起来这绝对不能保证?

因此,无论如何,您都必须对 file1 进行单遍处理,因此关键是优化循环内的处理(通过 file1 行)。考虑一次性处理 file2 的所有片段吗? (而不是涉及两个文件的多个操作。)

【讨论】:

  • 实际上,file1 中被替换的字节数与来自 file2 的字节数相匹配,因此我可以按照您的建议使用随机访问操作 - 我没有意识到这可能是我的问题。我使用 dd 从 file2 中提取块并在 file1 中替换 - 这比我之前做的拆分文件快 30%。感谢您的帮助!
  • @D.Puetzer 酷!看到你最终得到的完整的dd 命令会很有趣,这样将来遇到这个问题的其他人就可以开始解决类似的问题。
【解决方案2】:

按照 Jeff Y 的建议,我使用 dd 命令在字节级别有效地进行替换。我首先使用以下方法从 file2 中提取一个块:

dd if="file2" bs="$bperelem" skip="$start_copy" count=1 of="tmp2" 2> /dev/null

其中bperelem是块的字节数,start_copy是它所在的位置。然后我使用以下代码将其替换为 file1:

dd if="tmp2" bs="$bperelem" skip=0 count=1 seek="$start_replace" of="file1" conv=notrunc 2> /dev/null

对于我的具体问题,变量 start_copystart_replace 在 while 循环内更新。

【讨论】:

    猜你喜欢
    • 2021-08-10
    • 2013-09-06
    • 1970-01-01
    • 2017-03-31
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    相关资源
    最近更新 更多