awk使用file1的范围搜索file2中的字段
我正在尝试使用awk查找文件2中的所有$2值(约30MB),即文件1中的$2和$3之间的值(约2GB)。如果file2的$2中的值在file1字段之间,则它将与file1中的$6值一起打印。file1和file2都是以制表符分隔的,并且都是所需的输出。如果没有要打印的内容,则处理下一行。下面的awk运行,但速度非常慢,已处理约1天,仍未完成。有没有更好的方法来解决这个问题,或者有更好的编程语言 file1中的$1、$2和$3以及file2中的$1和$2必须与file1中的$1匹配,并且在file1中的$2和$3范围内 因此,为了在输出中打印行,它必须匹配$1,并且在file2的$2和$3范围内 因此,由于file2中的行匹配file1中的$1,并且在$2和$3范围内,它将打印在输出中。 谢谢 文件1~3MB 文件2~80MB 所需的输出选项卡已分隔 awkawk使用file1的范围搜索file2中的字段,awk,Awk,我正在尝试使用awk查找文件2中的所有$2值(约30MB),即文件1中的$2和$3之间的值(约2GB)。如果file2的$2中的值在file1字段之间,则它将与file1中的$6值一起打印。file1和file2都是以制表符分隔的,并且都是所需的输出。如果没有要打印的内容,则处理下一行。下面的awk运行,但速度非常慢,已处理约1天,仍未完成。有没有更好的方法来解决这个问题,或者有更好的编程语言 file1中的$1、$2和$3以及file2中的$1和$2必须与file1中的$1匹配,并且在file
它可能无效,但无论速度有多慢,都应该起作用:
$ 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的每个条目。它不会将2GB的文件读入内存,因此它仍然可以像您的版本一样进行较少的查找
您可以通过使用{print a[i]\t$6;delete a[i]}替换print a[i]\t$6来加快速度
编辑:在输出中添加分隔的选项卡,并刷新输出以反映更改的数据。打印\t就足够了,因为文件已经用制表符分隔,并且记录在任何时候都不会重新生成。这可能无效,但应该可以工作,尽管速度很慢:
$ 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的每个条目。它不会将2GB的文件读入内存,因此它仍然可以像您的版本一样进行较少的查找
您可以通过使用{print a[i]\t$6;delete a[i]}替换print a[i]\t$6来加快速度
编辑:在输出中添加分隔的选项卡,并刷新输出以反映更改的数据。打印\t就足够了,因为文件已经用制表符分隔,并且记录在任何时候都不会重新生成。一种可能的方法是使用AWK生成另一个AWK文件。内存消耗应该很低,因此对于一个非常大的文件1来说,这可能是一个救命稻草。至于速度,这可能取决于AWK实现的智能程度。我还没有机会在巨大的数据集上尝试它;我对你的发现很好奇 创建文件step1.awk: 通过管道将输出传输到文件step2.awk,并将其应用于文件2: 备选方案:生成C 我重写了step1.awk,使其生成C而不是awk代码。这不仅可以解决您之前报告的内存问题;考虑到C被编译成本机代码的事实,它也会快得多
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 "}";
}
样本输出:
$ awk -f step1.awk file1 > step2.c
$ cc step2.c -o step2
$ ./step2 < file2
1 949800 . T G ISG15
2 900000 rs123 - A AGRN
一种可能的方法是使用AWK生成另一个AWK文件。内存消耗应该很低,因此对于一个非常大的文件1来说,这可能是一个救命稻草。至于速度,这可能取决于AWK实现的智能程度。我还没有机会在巨大的数据集上尝试它;我对你的发现很好奇 创建文件step1.awk: 通过管道将输出传输到文件step2.awk,并将其应用于文件2: 备选方案:生成C 我重写了step1.awk,使其生成C而不是awk代码。这不仅可以解决您之前报告的内存问题;考虑到C被编译成本机代码的事实,它也会快得多
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 "}";
}
样本输出:
$ awk -f step1.awk file1 > step2.c
$ cc step2.c -o step2
$ ./step2 < file2
1 949800 . T G ISG15
2 900000 rs123 - A AGRN
如果性能是个问题,则必须按“开始”的值和范围对这两个文件进行排序 对文件进行排序后,您的扫描可以是增量的,因此速度更快 这是一个未经测试的脚本
$ awk '{line=$0; k=$2;
getline < "file1";
while (k >= $2) getline < "file1";
if(k <= $3) print line, $NF}' file2
如果性能是个问题,则必须按“开始”的值和范围对这两个文件进行排序 对文件进行排序后,您的扫描可以是增量的,因此速度更快 这是一个未经测试的脚本
$ awk '{line=$0; k=$2;
getline < "file1";
while (k >= $2) getline < "file1";
if(k <= $3) print line, $NF}' file2
您可以尝试在gawk中使用多数组从文件1创建dict,这是一种更高效的计算方法。与文件2相比,文件1的大小较小
您可以尝试在gawk中使用多数组从文件1创建dict,这是一种更高效的计算方法。与文件2相比,文件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
在这里逐个读取文件,首先读取文件输入文件2,然后在这里输入文件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
在此处逐个读取文件,首先读取文件输入\u file2,然后在此处输入\u file1。这将比您拥有的更快,因为它只循环遍历与文件2中具有相同$1值的文件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
不幸的是,对于未分类的输入,您没有太多的选项来加快它。如果文件1中的范围可以相互重叠,则删除b
reak.这将比您拥有的更快,因为它只循环遍历与file2中具有相同$1值的file1内容,并在找到匹配的范围后停止搜索:
$ 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中的范围可以相互重叠,则删除中断。我添加了一个编辑,因为需要一个额外的字段,但我不确定如何合并它。谢谢:。我收到以下错误:awk:awkgram.y:5015:find_line:Assertion lineno>0'失败。中止核心转储`并将在帖子中发布更多详细信息。非常感谢:。@Chris考虑到错误的严重性,可能是AWK内存不足。我对记忆消耗的乐观是错误的;我认为AWK会将step2.AWK的全部解析内容存储在内存中。@Ruud嗯,是的,AWK必须读取脚本文件step2.AWK的内容才能执行它,因此如果这太大,可能会导致问题。@Chris我重写脚本生成C而不是AWK。这应该可以解决内存问题,并大大提高性能。我添加了一个编辑,因为需要添加一个字段,但我不确定如何合并它。谢谢:。我收到以下错误:awk:awkgram.y:5015:find_line:Assertion lineno>0'失败。中止核心转储`并将在帖子中发布更多详细信息。非常感谢:。@Chris考虑到错误的严重性,可能是AWK内存不足。我对记忆消耗的乐观是错误的;我认为AWK会将step2.AWK的全部解析内容存储在内存中。@Ruud嗯,是的,AWK必须读取脚本文件step2.AWK的内容才能执行它,因此如果这太大,可能会导致问题。@Chris我重写脚本生成C而不是AWK。这将解决内存问题并极大地提高性能。如果getline出现故障,这将进入无限循环,有关如何安全地调用getline的信息,请参阅。感谢所有优秀的解决方案、解释和帮助。我真的很感激,因为我的数据集只会越来越大。谢谢:。如果getline出现故障,这将进入无限循环,请参阅以了解如何安全地调用getline。感谢大家提供的优秀解决方案、解释和帮助。我真的很感激,因为我的数据集只会越来越大。谢谢:。我编辑了这篇文章,希望能有所帮助。谢谢:。2 900000 rs123-A或2 900000 rs123-A AGRN是否在所需的输出中?抱歉,这是正确的:2 900000 rs123-A AGRN。在职位上也做了改变。谢谢:。如果您需要测试这些解决方案的部分或全部,我很想听听它们的执行时间?我会测试它们,并在有机会时报告执行时间。年底总是很忙。但我肯定会测试所有这些伟大的解决方案。谢谢:。我编辑了这篇文章,希望能有所帮助。谢谢:。2 900000 rs123-A或2 900000 rs123-A AGRN是否在所需的输出中?抱歉,这是正确的:2 900000 rs123-A AGRN。在职位上也做了改变。谢谢:。如果您需要测试这些解决方案的部分或全部,我很想听听它们的执行时间?我会测试它们,并在有机会时报告执行时间。年底总是很忙。但我肯定会测试所有这些伟大的解决方案。谢谢您:。
awk '
NR==FNR{for(i=$2;i<=$3;++i) d[$1,i] = $6; next}
d[$1,$2]{print $0, d[$1,$2]}' file1 file2
1 949800 . T G ISG15
2 900000 rs123 - A AGRN
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
$ 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