我想在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
是否有更快的替代品?
由于
答案 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;
}