unix AWK每1GB输出一次,而不是100,000行

gorkyyrv  于 2022-11-23  发布在  Unix
关注(0)|答案(1)|浏览(167)

我有一个42 GB /620万行的xml文件,我试图将其分解为可管理的大小(它们必须小于1 GB)。目前,我有一个每100,000行创建一个新文件的进程,它工作正常,但它生成了62个文件,这些文件的大小差异很大-从600 MB到1100 MB不等。
如果我可以重写脚本来处理大小限制,我应该在下面的步骤中处理更少的文件。
每一行都以<ent>开始,以</ent>结束。
是否有办法修改此脚本,使其每900 MB而不是每100,000行输出一个新文件?
这是我现在的脚本。请注意,我不是特别了解这一切,我已经通过谷歌和试验和错误到这一点。

BEGIN { new_chunk = 1 ; size = 100000 }

NR == 1 { header = $0 ; footer = "</" substr($1,2) ">" ; next }

$0 !~ footer {
  if (new_chunk) {
    outfile = "ent_" sprintf("%07d", num) ".xml"
    print header > outfile
    new_chunk = 0
  }
print > outfile
}

/<ent>/ {
  num = int(count++/size)
  if (num > prev_num) {
    print footer > outfile
    new_chunk = 1
  }
prev_num = num
}

END { if (!new_chunk) print footer > outfile }

非常感谢您的光临

cigdeys3

cigdeys31#

OP还没有提供一个输入文件样本,所以对OP的当前代码进行逆向工程,我提供了这个(假的)文件用于演示:

$ cat input.xml
<some header record>
<ent> line1 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line2 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line3 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line4 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line5 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line6 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line7 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line8 : 12345678901234567890123456789012345678901234567890</ent>
</some>

一个awk创意:

awk -v maxsize='250' '                                 # replace "250" with max file size

function switch_file(op) {
    if (outfile)
       print footer > outfile
    close(outfile)
    if (op != "end") {                                 # if op == "end" do not bother with creating a new file
       outfile="ent_" sprintf("%07d",++c) ".xml"
       print header > outfile
       size=len_hdr
    }
}

NR==1   { header=$0
          len_hdr=length(header)+1                     # "+1" for trailing "\n"
          footer="</" substr($1,2) ">"
          len_ftr=length(footer)+1                     # "+1" for trailing "\n"
          switch_file()
        }

/<ent>/ { len_curr=length($0)+1                        # "+1" for trailing "\n"
          if (size + len_curr + len_ftr > maxsize)
             switch_file()
          print $0 > outfile
          size+=len_curr
        }

END     { switch_file("end") }                         # terminate the current outfile

' input.xml

**注意:**如注解中所述,length()函数返回字符数(而不是字节数),因此如果输入文件包含多字节字符,则此代码将少计字节数;处理多字节字符在awk中是可行的,但是需要更多的编码和/或扩展

这会产生:

$ head ent_*xml
==> ent_0000001.xml <==
<some header record>
<ent> line1 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line2 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line3 : 12345678901234567890123456789012345678901234567890</ent>
</some>

==> ent_0000002.xml <==
<some header record>
<ent> line4 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line5 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line6 : 12345678901234567890123456789012345678901234567890</ent>
</some>

==> ent_0000003.xml <==
<some header record>
<ent> line7 : 12345678901234567890123456789012345678901234567890</ent>
<ent> line8 : 12345678901234567890123456789012345678901234567890</ent>
</some>

$ wc ent_*xml
  5  16 242 ent_0000001.xml          # total size(242) < 250
  5  16 242 ent_0000002.xml          # total size(242) < 250
  4  12 171 ent_0000003.xml          # total size(171) < 250
 14  44 655 total

相关问题