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

时间:2016-12-21 12:47:27

标签: awk

我正在尝试使用awk查找$2file2的所有~30MB值,这些值在$2和{{1}之间} $3中约为2GB。如果file1的{​​{1}}中的值介于$2字段之间,那么它将与file2中的file1值一起打印。 $6file1都是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以及$3file2范围内的行匹配,因此会在输出中打印。 谢谢你:)。

file1 (~3MB)

file2

file2 (~80MB)

$1

所需的输出 file1

$2

AWK

$3

6 个答案:

答案 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

替代方案:生成C

我重写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创建一个字典,这是更高效的计算(gawkfile1相比尺寸较小),

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。