awk使用file1的范围搜索file2中的字段

awk使用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查找文件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

所需的输出选项卡已分隔

awk


它可能无效,但无论速度有多慢,都应该起作用:

$ 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