有没有更快的方法来截断Unix中的列

时间:2013-01-08 23:38:44

标签: unix

我想在Unix中将第4列TSV文件截断为给定长度。文件有几百万的记录,大小为8GB。

我正在尝试这个,但似乎有点慢。

awk -F"\t" '{s=substr($4,0,256); print $1"\t"$2"\t"$3"\t"s"\t"$5"\t"$6"\t"$7}' file > newFile

是否有更快的替代品?

由于

3 个答案:

答案 0 :(得分:2)

您的命令可以更好地编写(假设您正在重新构建记录),这可能会提高性能:

awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,256) }' file > newFile

如果您可以访问多核计算机(您可能会这样做),则可以使用GNU parallel。你可能想要改变你使用的核心数量(我在这里设置了4)和用于awk的块大小(我把它设置为2兆字节)......

< file parallel -j 4 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' > newFile


以下是我在系统上使用2.7G文件进行的一些测试,该文件包含1亿行,块大小为2M:

time awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' file >/dev/null

结果:

real    1m59.313s
user    1m57.120s
sys     0m2.190s

有一个核心:

time < file parallel -j 1 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    2m28.270s
user    4m3.070s
sys     0m41.560s

有四个核心:

time < file parallel -j 4 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    0m54.329s
user    2m41.550s
sys     0m31.460s

有十二个核心:

time < file parallel -j 12 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    0m36.581s
user    2m24.370s
sys     0m32.230s

答案 1 :(得分:2)

我假设你的文件在字段之间只有一个空格字符,并且在行的开头没有空格。如果这是错误的,这可以增强。 否则,这应该工作:

sed 's/^\([^ ]* [^ ]* [^ ]* [^ ]\{1,256\}\)[^ ]* /\1 /'

我实际上没有使用256个字符长的数据进行测试(我用\{1,2\}进行了测试,我不知道它的速度与awk的速度相比.BTW,在某些版本上,你可能需要从花括号中留下反斜杠,只使用{1,256}

答案 2 :(得分:2)

如果斯科特或史蒂夫的解决方案仍然太慢,可能是时候打破C.以./a.out < file > newFile运行。首先测试一个带有一些长字段的小文件;我不是100%肯定我的数学是正确的。

#include <stdio.h>
int
main(void)
{
    int field = 1;
    int character = 0;
    int c;
    while ((c = getchar()) != EOF)
    {
        switch (c)
        {
        case '\n':
            field = 1;
            character = 0;
            break;
        case '\t':
            character = 0;
            field++;
            break;
        default:
            character++;
            break;
        }
        if (field != 4 || character < 256)
            putchar(c);
    }
    if (ferror(stdout) || fflush(stdout) || fclose(stdout))
    {
        perror("write");
        return 1;
    }
    return 0;
}