【问题标题】:Split a huge file in LINUX into multiple small files (each less than 100MB) splitting at a specific line with pattern match将 LINUX 中的一个大文件拆分为多个小文件(每个小于 100MB),在特定行拆分为模式匹配
【发布时间】:2017-02-21 21:29:17
【问题描述】:

我有以下源文件(~10GB),我需要分成几个小文件(每个

Inout.csv
        Src,AgentNum,PhoneNum
        DWH,Agent_1234,phone1  
        NULL,NULL,phone2  
        NULL,NULL,phone3 
        DWH,Agent_5678,phone1 
        NULL,NULL,phone2 
        NULL,NULL,phone3
        DWH,Agent_9999,phone1 
        NULL,NULL,phone2 
        NULL,NULL,phone3

Output1.csv
        Src,AgentNum,PhoneNum
        DWH,Agent_1234,phone1  
        NULL,NULL,phone2  
        NULL,NULL,phone3
Output2.csv
        Src,AgentNum,PhoneNum
        DWH,Agent_5678,phone1 
        NULL,NULL,phone2 
        NULL,NULL,phone3
        DWH,Agent_9999,phone1 
        NULL,NULL,phone2 
        NULL,NULL,phone3

#!/bin/bash
    #Calculate filesize in bytes
    FileSizeBytes=`du -b $FileName | cut -f1`

    #Check for the file size
    if [[ $FileSizeBytes -gt 100000000 ]]
    then
        echo "Filesize is greater than 100MB"
        NoOfLines=`wc -l < $FileName` 
        AvgLineSize=$((FileSizeBytes / NoOfLines))
        LineCountInEachFile=$((100000000 / AvgLineSize))

            #Section for splitting the files

    else
        echo "Filesize is already less than 100MB. No splitting needed"
        exit 0
    fi

我是 UNIX 新手,但我自己尝试这个 bash 脚本并且有点卡在拆分文件上。我不希望有人给我一个完整的脚本,我正在寻找任何简单的方法/建议,可能使用其他简单的替代方案,如 sed 等。非常感谢!

【问题讨论】:

  • 您可以使用 perl 吗?如果没有,你可以试试 awk。
  • 目前我只能在当前项目中使用 shell 脚本。但是,如果您有珍珠解决方案,我可以肯定地尝试。谢谢!

标签: linux bash sed grep


【解决方案1】:

步骤 1. 保存标题

第 2 步。创建一个变量“content”来临时保存程序要读取的内容

第 3 步。开始阅读下一行,在 python 中:

if line.startswith("DWH"):
    if content != "":
        #if the content.len() reaches your predefined size, output_your_header + content here and reinitiate content by 'content = ""'
        #else, content.len() is still under size limit, keep adding the new agent to content by doing 'content += line'
else:
    content += line

【讨论】:

  • 谢谢@dgg32,但我正在寻找 UNIX Shell 中的解决方案。
【解决方案2】:

这里有一个关于如何在 Perl 中执行此操作的粗略想法。如果正则表达式与您的实际数据不完全匹配,请修改它。我只在你的虚拟数据上进行了测试。

#!/usr/bin/perl -w    
my $l=<>; chomp($l); my $header=$l;
my $agent=""; my $fh;

while ($l=<>) {    
   chomp($l);
   if ($l=~m/^\s*[^,]+,(Agent_\d+),[^,]+/) {
       $agent="$1";
       open($fh,">","${agent}.txt") or die "$!";
       print $fh $header."\n";
   }
   print $fh $l."\n";
}

如下使用:

./perlscript.pl < inputfile.txt

如果您没有 perl(在 /usr/bin/perl 或其他类似位置检查 perl),我将尝试执行 awk 脚本。如果您在上述脚本中运行时发现问题,请告诉我。


响应您更新的请求,您只想拆分文件,每个输出文件小于 100MB,没有代理记录拆分到两个文件中,并且该标题打印在每个输出文件中,这里是大致了解如何做到这一点。它并不精确(因为您需要在编写之前进行计算)。如果您将 $maxfilesize 设置为 95*1024*1024 之类的值99*1024*1024,应该让你有一个小于 100MB 的文件(例如,如果代理记录的最大大小小于 5MB,那么设置 $maxfilesize95*1024*1024)

#!/usr/bin/perl -w    
# Max file size, approximately in bytes
#
# For 99MB make it as 99*1024*1024
#
my $maxfilesize=95*1024*1024;    
#my $maxfilesize=400;

my $l=<>; chomp($l); my $header=$l;

my $fh;
my $filecounter=0;
my $filename="";
my $filesize=1000000000000; # big dummy size for first iteration

while ($l=<>) {
   chomp($l);    
   if ($l=~m/^\s*[^,]+,Agent_\d+,[^,]+/) {
       if ($filesize>$maxfilesize) {
          print "FileSize: $filesize\n";
          $filecounter++; $filename=sprintf("outfile_%05d",$filecounter);
          print "Opening New File: $filename\n";
          open($fh,">","${filename}.txt") or die "$!";
          print $fh $header."\n";
          $filesize=length($header);
       }
   }
   print $fh $l."\n";
   $filesize+=length($l);
   print "FileSize: $filesize\n";
}

如果你想要比这更精确的切割,我会在打印前更新它缓冲数据。

【讨论】:

  • 感谢珍珠脚本!如果我没看错,我认为脚本会将文件拆分为每个代理的不同文件(每个代理一个文件)。但在我的要求中,每个输出文件可以有数百个代理,只要小于 100MB。我还没有尝试过这个脚本,如果我弄错了,很抱歉:)
  • 我明白了。所以,你只想有标题行,每个输出文件几千行(大小小于 100MB)?
  • 是的。只要每个文件小于 100MB 并且每个代理的记录不会在文件之间重叠(拆分应该发生在代理的所有记录的末尾,而不是在两者之间随机)。感谢您的及时回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 2019-09-23
  • 2013-12-11
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多