我正在尝试使用awk
查找$2
中file2
的所有~30MB
值,这些值在$2
和{{1}之间} $3
中约为2GB。如果file1
的{{1}}中的值介于$2
字段之间,那么它将与file2
中的file1
值一起打印。 $6
和file1
都是file1
以及file2
。如果没有要打印的内容,则处理下一行。下面的tab-delimited
运行但速度非常慢(已处理约1天但仍未完成)。有没有更好的方法来处理这个或更好的编程语言?
desired output
的{p> awk
和$1
及$2
以及$3
的{{1}}和file1
必须匹配$1
} $2
并且在file2
的{{1}}和$1
范围内。
因此,为了在输出中打印该行,它必须与file1
匹配,并且在$2
的{{1}}和$3
范围内
因此,由于file1
中的行与$1
中的$2
以及$3
和file2
范围内的行匹配,因此会在输出中打印。
谢谢你:)。
file1 (~3MB)
file2
file2 (~80MB)
$1
所需的输出 file1
$2
AWK
$3
答案 0 :(得分:2)
这比你所拥有的要快,因为它只循环遍历file2中与file2具有相同$ 1值的内容,并在找到匹配的范围后停止搜索:
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR==FNR {
c = ++num[$1]
beg[$1][c] = $2
end[$1][c] = $3
val[$1][c] = $NF
next
}
$1 in val {
for (c=1; c<=num[$1]; c++) {
if ( (beg[$1][c] <= $2) && ($2 <= end[$1][c]) ) {
print $0, val[$1][c]
break
}
}
}
$ awk -f tst.awk file1 file2
1 949800 . T G ISG15
2 900000 rs123 - A AGRN
不幸的是,对于未分类的输入,因为没有太多的选项可以让它更快。如果file1中的范围可以相互重叠,则删除&#34; break&#34;。
答案 1 :(得分:1)
它可能无效,但应该有效,无论多慢:
$ awk 'NR==FNR{ a[$2]=$0; next }
{ for(i in a)
if(i>=$2 && i<=$3) print a[i] "\t" $6 }
' f2 f1
1 949800 . T G ISG15
3 900000 . C - AGRN
基本上它会读取内存中的file2
,并且对于file1
中的每一行,它都会通过file2
的每个条目(在内存中)。它不会将2 GB的文件读入内存,因此它的版本仍然不那么高了。
您可以将print a[i] "\t" $6
替换为{print a[i] "\t" $6; delete a[i]}
来加快速度。
编辑:添加了分隔符以输出并刷新输出以反映更改的数据。打印"\t"
就足够了,因为文件已经以制表符分隔,并且记录不会在任何时候重建。
答案 2 :(得分:1)
一种可能的方法是使用AWK生成另一个AWK文件。内存消耗应该很低,所以对于真的大file1
这可能是一个救星。至于速度,这可能取决于AWK实现的智能程度。我还没有机会在庞大的数据集上尝试它;我很好奇你的发现。
创建文件step1.awk
:
{
sub(/^chr/, "", $1);
print "$1==\"" $1 "\" && " $2 "<$2 && $2<" $3 " { print $0 \"\\t" $6 "\"; }";
}
将其应用于file1
:
$ awk -f step1.awk file1
$1=="1" && 948953<$2 && $2<948956 { print $0 "\tISG15"; }
$1=="1" && 949363<$2 && $2<949858 { print $0 "\tISG15"; }
将输出传递给文件step2.awk
并将其应用于file2
:
$ awk -f step1.awk file1 > step2.awk
$ awk -f step2.awk file2
1 949800 rs201725126 T G ISG15
我重写step1.awk
,使其生成C而不是AWK代码。这不仅可以解决您之前报告的内存问题;考虑到C被编译为本机代码这一事实,它也将更快地 lot 。
BEGIN {
print "#include <stdio.h>";
print "#include <string.h>";
print "int main() {";
print " char s[999];";
print " int a, b;";
print " while (fgets(s, sizeof(s), stdin)) {";
print " s[strlen(s)-1] = 0;";
print " sscanf(s, \"%d %d\", &a, &b);";
}
{
print " if (a==" $1 " && " $2 "<b && b<" $3 ") printf(\"%s\\t%s\\n\", s, \"" $6 "\");";
}
END {
print " }";
print "}";
}
鉴于您的样本file1
,这将生成以下C源:
#include <stdio.h>
#include <string.h>
int main() {
char s[999];
int a, b;
while (fgets(s, sizeof(s), stdin)) {
s[strlen(s)-1] = 0;
sscanf(s, "%d %d", &a, &b);
if (a==1 && 948953<b && b<948956) printf("%s\t%s\n", s, "ISG15");
if (a==1 && 949363<b && b<949858) printf("%s\t%s\n", s, "ISG15");
if (a==2 && 800000<b && b<900500) printf("%s\t%s\n", s, "AGRN");
}
}
示例输出:
$ awk -f step1.awk file1 > step2.c
$ cc step2.c -o step2
$ ./step2 < file2
1 949800 . T G ISG15
2 900000 rs123 - A AGRN
答案 3 :(得分:1)
如果性能问题,您必须按值(和范围开始)对两个文件进行排序。
对文件进行排序,您的扫描可以是增量的(因此更快)
这是一个未经测试的脚本
$ awk '{line=$0; k=$2;
getline < "file1";
while (k >= $2) getline < "file1";
if(k <= $3) print line, $NF}' file2
答案 4 :(得分:1)
您可以尝试使用iostat -x 1 2 | sed 's/,/./g' | awk '
BEGIN {
disk = -1;
}
/^avg-cpu/ {c++; a=2}
c==2 && a && !--a {printf ("%s,%s,%s,", $1, $3, $4)}
c==2 && /^sda/ { disk=$14;}
c==2 && /^sdb/ { disk=$14; }
c==2 && /^nvme0n1/ { disk=$14; }
END {
printf("%s", disk);
}
'
中的多个阵列从file1
创建一个字典,这是更高效的计算(gawk
与file1
相比尺寸较小),
file2
你明白了,
awk '
NR==FNR{for(i=$2;i<=$3;++i) d[$1,i] = $6; next}
d[$1,$2]{print $0, d[$1,$2]}' file1 file2
答案 5 :(得分:1)
请您试着跟随并告诉我这是否对您有帮助。
awk 'FNR==NR{A[$1]=$0;B[$1,++D[$1]]=$2;next} {++C[$1]}($2<B[$1,C[$1]] && $3>B[$1,C[$1]]){print A[$1]}' Input_file2 Input_file1
在这里逐个读取文件,首先读取文件Input_file2,然后读取Input_file1。