簡體   English   中英

使用 AWK 和 BASH 將大型壓縮文件拆分為多個輸出

[英]Split a large, compressed file into multiple outputs using AWK and BASH

我有一個大 (3GB) 的 gzip 文件,其中包含兩個字段:NAME 和 STRING。 我想將此文件拆分為較小的文件 - 如果字段一是 john_smith,我希望將字符串放在 john_smith.gz 中。 注意:字符串字段可以並且確實包含特殊字符。

我可以使用 BASH 在域上的 for 循環中輕松完成此操作,但我更喜歡使用 AWK 一次讀取文件的效率。

我嘗試在 awk 中使用系統 function 並在字符串周圍使用轉義單引號

zcat 大文件.gz | awk '{system("echo -e '"'"'"$1"\t"$2"'"'"' | gzip >> "$1".gz");}'

它在大多數行上都能正常工作,但是其中一些被打印到 STDERR 並給出 shell 無法執行命令的錯誤(shell 認為字符串的一部分是命令)。 看起來特殊字符可能會破壞它。

關於如何解決這個問題的任何想法,或者任何有幫助的替代實現?

謝謝!

-肖恩

您正面臨時間與磁盤空間的巨大權衡。 我假設您正在嘗試通過將記錄附加到 ${name}.gz 文件的末尾來節省空間。 @sehe 評論和代碼絕對值得考慮。

無論如何,您的時間比 3 GB 的磁盤空間更有價值。 為什么不試試

 zcat large_file.gz \
 | awk '-F\t' { 
    name=$1; string=$2; outFile=name".txt"
    print name "\t" string >> outFile
    # close( outFile) 
   }'

 echo *.txt | xargs gzip -9

您可能需要取消注釋 #close(outFile)。 包含 xargs 是因為我假設您將創建超過 1000 個文件名。 即使您不這樣做,使用該技術也不會受到傷害。

請注意,此代碼假定使用制表符分隔的數據,根據需要更改 -F 的 arg 值以及打印語句中的“\t”以提供所需的字段分隔符。

沒時間測試這個。 如果您喜歡這個想法並遇到困難,請發布小樣本數據、預期的 output 以及您收到的錯誤消息。

我希望這有幫助。

創建這個程序,比如largesplitter.c並使用命令

zcat large_file.gz | largesplitter

朴素的程序是:

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main (void)
{
        char    buf [32000];  // todo:  resize this if the second field is larger than 
        char    cmd [120];
        long    linenum = 0;
        while (fgets (buf, sizeof buf, stdin))
        {
                ++linenum;
                char *cp = strchr (buf, '\t');   // identify first field delimited by tab
                if (!cp)
                {
                        fprintf (stderr, "line %d missing delimiter\n", linenum);
                        continue;
                }
                *cp = '\000';  // split line
                FILE *out = fopen (buf, "w");
                if (!out)
                {
                        fprintf (stderr, "error creating '%s': %s\n", buf, strerror(errno));
                        continue;
                }
                fprintf (out, "%s", cp+1);
                fclose (out);
                snprintf (cmd, sizeof cmd, "gzip %s", buf);
                system (cmd);
        }
        return 0;
}

這在我的系統上編譯沒有錯誤,但我沒有測試它的功能。

也許嘗試以下方式:

zcat large_file.gz | echo $("awk '{system("echo -e '"'"'"$1"\t"$2"'"'"' | gzip >> "$1".gz");}'")

我自己沒有嘗試過,因為我沒有任何大文件可以玩。

這個小 perl 腳本很好地完成了這項工作

  • 保持所有目標文件打開以提高性能
  • 進行錯誤基本處理
  • 現在編輯還通過 gzip 即時通過gzip管道 output

$fh有點雜亂無章,因為顯然直接使用 hash 條目不起作用

#!/usr/bin/perl
use strict;
use warnings;

my $suffix = ".txt.gz";

my %pipes;
while (my ($id, $line) = split /\t/,(<>),2)
{
    exists $pipes{$id} 
        or open ($pipes{$id}, "|gzip -9 > '$id$suffix'") 
        or die "can't open/create $id$suffix, or cannot spawn gzip";

    my $fh = $pipes{$id};
    print $fh $line;
}

print STDERR "Created: " . join(', ', map { "$_$suffix" } keys %pipes) . "\n"

哦,像這樣使用它

zcat input.gz | ./myscript.pl

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM