代码之家  ›  专栏  ›  技术社区  ›  17th Lvl Botanist

在Unix中拆分文件而不分隔以相似值开头的行

  •  0
  • 17th Lvl Botanist  · 技术社区  · 8 年前

    我有一个分类的。类似以下内容的csv文件:

    AABB1122,ABC,BLAH,4
    AABB1122,ACD,WHATEVER,1
    AABB1122,AGT,CAT,4
    CCDD4444,AYT,DOG,4
    CCDD4444,ACG,MUMMY,8
    CCEE4444,AOP,RUN,5
    DDFF9900,TUI,SAT,33
    DDFF9900,WWW,INDOOR,5
    

    我想将文件拆分为较小的文件,每个文件大约有两行,但我不想将第一列中具有相同值的行分隔开。

    在这里,我将得到三个文件:

    x00000:

    AABB1122,ABC,BLAH,4
    AABB1122,ACD,WHATEVER,1
    AABB1122,AGT,CAT,4
    

    x00001:

    CCDD4444,AYT,DOG,4
    CCDD4444,ACG,MUMMY,8
    

    x00002:

    CCEE4444,AOP,RUN,5
    DDFF9900,TUI,SAT,33
    DDFF9900,WWW,INDOOR,5 
    

    我的实际数据大小约为7 Gig,包含超过1亿行。我想把它分成大约100K行或6MB的文件。我可以使用文件大小或行号进行拆分。

    我知道我可以使用“排序”进行拆分,例如:

    split -a 5 -d -1 2
    

    在这里,这将给我四个文件,在大多数情况下,第一列中的值将被拆分为文件。

    我想我可能需要awk,但是,即使在阅读了手册之后,我也不知道如何继续。

    感谢您的帮助!谢谢

    2 回复  |  直到 8 年前
        1
  •  2
  •   Kusalananda    8 年前

    awk 脚本:

    BEGIN   { FS = ","  }
    !name   { name = sprintf("%06d-%s.txt", NR, $1) }
    
    count >= 2 && prev != $1  {
        close(name)
        name = sprintf("%06d-%s.txt", NR, $1)
        count = 0
    }
    
    {
        print >name
        prev = $1
        ++count
    }
    

    对给定数据运行此操作将创建三个文件:

    $ awk -f script.awk file.csv
    
    $ cat 000001-AABB1122.txt
    AABB1122,ABC,BLAH,4
    AABB1122,ACD,WHATEVER,1
    AABB1122,AGT,CAT,4
    
    $ cat 000004-CCDD4444.txt
    CCDD4444,AYT,DOG,4
    CCDD4444,ACG,MUMMY,8
    
    $ cat 000006-CCEE4444.txt
    CCEE4444,AOP,RUN,5
    DDFF9900,TUI,SAT,33
    DDFF9900,WWW,INDOOR,5
    

    我任意选择使用第一行所在的原始文件中的行号,以及该行上第一个字段的数据作为文件名。

    脚本统计打印到当前输出文件的行数,如果该数字大于或等于2,并且如果第一个字段的值不同于前一行的第一个字段,则关闭当前输出文件,构造新的输出名称,并重置计数。

    最后一个块只打印到当前文件名,记住 prev 变量,并递增计数。

    这个 BEGIN 块初始化字段分隔符(在读取第一行之前)和 !name 块设置初始输出文件名(读取第一行时)。


    要准确获取问题中的文件名,请使用

    name = sprintf("x%05d", ++n)
    

    在执行此操作的两个位置设置输出文件名。

        2
  •  0
  •   ctac_    8 年前

    如果可用,请使用csplit

    使用给定数据

    csplit -s infile %^A% /^C/ %^C% /^D/ /^Z/ {*}