【问题标题】:Splitting large files efficiently (currently using awk)高效分割大文件(目前使用 awk)
【发布时间】:2016-02-19 12:28:48
【问题描述】:

我有一个 4 GB 的文件,我需要对其进行一些操作。我有一个 Bash 脚本来执行此操作,但 Bash 似乎不适合将大型数据文件读入数组。所以我决定用 awk 分解我的文件。

我当前的脚本是:

for((i=0; i<100; i++)); do awk -v i=$i 'BEGIN{binsize=60000}{if(binsize*i < NR && NR <= binsize*(i+1)){print}}END{}' my_large_file.txt &> my_large_file_split$i.fastq; done

然而,这个脚本的问题是它会读入并循环这个大文件 100 次(这大概会导致大约 400GB 的 IO)。

问题:有没有更好的读取大文件的策略?也许在 awk 中写入文件而不是重定向其输出?

【问题讨论】:

  • 为什么不直接使用split(1)
  • 这似乎也是一个合理的解决方案。

标签: bash awk split


【解决方案1】:

假设binsize 是您希望每个块的行数,您可以在单步执行文件时维护和重置行计数器,并在 awk 中设置备用输出文件,而不是使用 shell 进行重定向。

awk -v binsize=60000 '
  BEGIN {
    outfile="output_chunk_1.txt"
  }
  count > binsize {
    if (filenum>1) {
      close(outfile)
    }
    filenum++
    outfile="output_chunk_" filenum ".txt"
    count=0
  }
  {
    count++
    print > outfile
  }
' my_large_file.txt

我还没有实际测试过这段代码,所以如果它不能逐字运行,至少它应该让您了解要使用的策略。 :-)

我们的想法是,我们将单步执行文件,只要块的行数超过binsize,就更新变量中的文件名。请注意,close(outfile) 不是绝对必要的,因为 awk 在退出时当然会关闭所有打开的文件,但它可以为每个打开的文件句柄节省几个字节的内存(只有在你有很多输出文件)。


也就是说,你可以单独在 bash 中做几乎完全相同的事情:

#!/usr/bin/env bash

binsize=60000

filenum=1; count=0

while read -r line; do

  if [ $count -gt $binsize ]; then
    ((filenum++))
    count=0
  fi

  ((count++))

  outfile="output_chunk_${filenum}.txt"
  printf '%s\n' "$line" >> $outfile

done < my_large_file.txt

(也未经测试。)

虽然我期望 awk 解决方案比 bash 更快,但自己做基准测试可能不会有什么坏处。 :)

【讨论】:

  • 我还没有机会测试您的特定脚本,但是将 awk 输出到单独文件的关键是 outfile="output_chunk_" filenum ".txt"print &gt; outfile(我在解决这个问题时使用了它们)。与我的原始脚本(我预计需要 800 分钟)相比,此方法大约需要 30 分钟才能完成。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-02
相关资源
最近更新 更多