Join awk错误:无法分配内存

Join awk错误:无法分配内存,join,awk,Join,Awk,我有两个文件,如下图所示,以制表符分隔: 归档 chr1 123 aa b c d chr1 234 a b c d chr1 345 aa b c d chr1 456 a b c d .... 文件B xxxx abcd chr1 123 aa c d e yyyy defg chr1 345 aa e f g ... 我想用“chr1”、“123”连接两个基于2列的文件,并将前两列从文件B添加到

我有两个文件,如下图所示,以制表符分隔:

归档

chr1   123 aa b c d
chr1   234 a  b c d
chr1   345 aa b c d
chr1   456 a  b c d
....
文件B

xxxx  abcd    chr1   123    aa    c    d    e
yyyy  defg    chr1   345    aa    e    f    g
...
我想用“chr1”、“123”连接两个基于2列的文件,并将前两列从文件B添加到文件A

awk 'NR==FNR{a[$3,$4]=$1OFS$2;next}{$7=a[$1,$2];print}' OFS='\t' fileb filea
输出:

chr1   123    aa    b    c    d    xxxx    abcd
chr1   234    a     b    c    d
chr1   345    aa    b    c    d    yyyy    defg
chr1   456    a     b    c    d

然而,对于实际数据,fileb太大,它返回一个错误:“无法分配6400字节的内存(无法分配内存)”。是否有人可以提供一种替代方法来执行此操作,以便以较小的部分读取文件。

一种快速而肮脏的技术是操作输入数据并使用
连接

$ awk '{print $3"-"$4,$1,$2}' fileb | sort > fileb2
$ awk '{print $1"-"$2,$3,$4,$5}' filea | sort > filea2
$ join -a1 filea2 fileb2
chr1-123 aa b c xxxx abcd
chr1-234 a b c
chr1-345 aa b c yyyy defg
chr1-456 a b c

如有必要,可以去掉第一列中的-。请注意,这是不健全的,购买可能是足够的
join
可能需要比
awk
更少的内存,并且能够处理输入…或者它可能不需要

一种快速而肮脏的技术是操作输入数据并使用
join

$ awk '{print $3"-"$4,$1,$2}' fileb | sort > fileb2
$ awk '{print $1"-"$2,$3,$4,$5}' filea | sort > filea2
$ join -a1 filea2 fileb2
chr1-123 aa b c xxxx abcd
chr1-234 a b c
chr1-345 aa b c yyyy defg
chr1-456 a b c
如有必要,可以去掉第一列中的-。请注意,这是不健全的,购买可能是足够的
join
可能需要比
awk
更少的内存,并且能够处理输入…或者它可能不需要

您可以尝试以下代码:

#!/usr/bin/awk -f

BEGIN {
    file1 = ARGV[1]
    file2 = ARGV[2]
    LIMIT = 1000
    OFS = "\t"
    i = 0
    while ((getline < file2) > 0) {
        key = $3 "\x1c" $4
        if (!(key in a)) {
            a[key] = $1 OFS $2
            if (i == LIMIT) {
                break
            }
        }
    }
    while ((getline < file1) > 0) {
        key = $1 "\x1c" $2
        if (key in a) {
            $7 = a[key]
            print
            delete a[key]
            while ((getline < file2) > 0) {
                key = $3 "\x1c" $4
                if (!(key in a)) {
                    a[key] = $1 OFS $2
                    break
                }
            }
        } else {
            $7 = ""
            print
        }
    }
    exit 0
}
#/usr/bin/awk-f
开始{
file1=ARGV[1]
file2=ARGV[2]
限额=1000
OFS=“\t”
i=0
而((getline0){
密钥=$3“\x1c”$4
如果(!(输入a)){
a[键]=1美元/2美元
如果(i==限制){
打破
}
}
}
而((getline0){
密钥=$1“\x1c”$2
如果(输入a){
$7=一把[钥匙]
打印
删除[键]
而((getline0){
密钥=$3“\x1c”$4
如果(!(输入a)){
a[键]=1美元/2美元
打破
}
}
}否则{
$7 = ""
打印
}
}
出口0
}
用法:
awk-f script.awk filea fileb

您可以尝试以下代码:

#!/usr/bin/awk -f

BEGIN {
    file1 = ARGV[1]
    file2 = ARGV[2]
    LIMIT = 1000
    OFS = "\t"
    i = 0
    while ((getline < file2) > 0) {
        key = $3 "\x1c" $4
        if (!(key in a)) {
            a[key] = $1 OFS $2
            if (i == LIMIT) {
                break
            }
        }
    }
    while ((getline < file1) > 0) {
        key = $1 "\x1c" $2
        if (key in a) {
            $7 = a[key]
            print
            delete a[key]
            while ((getline < file2) > 0) {
                key = $3 "\x1c" $4
                if (!(key in a)) {
                    a[key] = $1 OFS $2
                    break
                }
            }
        } else {
            $7 = ""
            print
        }
    }
    exit 0
}
#/usr/bin/awk-f
开始{
file1=ARGV[1]
file2=ARGV[2]
限额=1000
OFS=“\t”
i=0
而((getline0){
密钥=$3“\x1c”$4
如果(!(输入a)){
a[键]=1美元/2美元
如果(i==限制){
打破
}
}
}
而((getline0){
密钥=$1“\x1c”$2
如果(输入a){
$7=一把[钥匙]
打印
删除[键]
而((getline0){
密钥=$3“\x1c”$4
如果(!(输入a)){
a[键]=1美元/2美元
打破
}
}
}否则{
$7 = ""
打印
}
}
出口0
}

用法:
awk-f script.awk filea fileb

这将以速度交换内存:

$ cat tst.awk                
BEGIN{
    FS=OFS="\t"
    lookup = ARGV[--ARGC]
    delete ARGV[ARGC]
}
{
    found = 0
    while ( !found && ((getline str < lookup) > 0) ) {
        split(str,arr)
        if ( ($1 == arr[3]) && ($2 == arr[4]) ) {
            $0 = $0 OFS arr[1] OFS arr[2]
            found = 1
        }
    }
    close(lookup)
    print
}
$ gawk -f tst.awk fileA fileB
chr1    123     aa      b       c       d       xxxx    abcd
chr1    234     a       b       c       d
chr1    345     aa      b       c       d       yyyy    defg
chr1    456     a       b       c       d
$cat tst.awk
开始{
FS=OFS=“\t”
查找=ARGV[--ARGC]
删除ARGV[ARGC]
}
{
找到=0
而(!found&((getline str0)){
拆分(str、arr)
如果($1==arr[3])&($2==arr[4])){
$0=$0 OFS arr[1]OFS arr[2]
发现=1
}
}
关闭(查找)
打印
}
$gawk-f tst.awk文件a文件b
chr1 123 aa b c d xxxx abcd
chr1 234 a b c d
chr1 345 aa b c d yyyy定义
chr1 456 a b c d
它使用几乎为零的内存,因为它不在内部存储任何值,但速度会很慢,因为对于fileA中的每一行,它会读取fileB中的每一行,直到找到匹配项,与您已经尝试的相反,您尝试从fileB读取所有行并将它们存储为由字段3和4键入的数组元素,在这种情况下,它将是fileA的每一行的内部哈希查找,而不是外部线性搜索

如果fileA中有许多键在fileB中不存在,那么可以通过在第3和第4个字段中对fileB进行排序,然后将getline循环中的测试更改为类似以下内容,从而大大提高速度:

        if ( ($1 FS $2) == (arr[3] FS arr[4]) ) {
            $0 = $0 OFS arr[1] OFS arr[2]
            found = 1
        }
        else (if ($1 FS $2) < (arr[3] FS arr[4]) ) {
            found = 1
        }
if($1 FS$2)==(arr[3]FS arr[4])){
$0=$0 OFS arr[1]OFS arr[2]
发现=1
}
其他(如果($1 FS$2)<(arr[3]FS arr[4])){
发现=1
}

您可以找到正确的逻辑-希望您能想到,当您从文件A中查找的值可能存在于已排序的文件B中时,您希望停止循环。

这可以为内存交换速度:

$ cat tst.awk                
BEGIN{
    FS=OFS="\t"
    lookup = ARGV[--ARGC]
    delete ARGV[ARGC]
}
{
    found = 0
    while ( !found && ((getline str < lookup) > 0) ) {
        split(str,arr)
        if ( ($1 == arr[3]) && ($2 == arr[4]) ) {
            $0 = $0 OFS arr[1] OFS arr[2]
            found = 1
        }
    }
    close(lookup)
    print
}
$ gawk -f tst.awk fileA fileB
chr1    123     aa      b       c       d       xxxx    abcd
chr1    234     a       b       c       d
chr1    345     aa      b       c       d       yyyy    defg
chr1    456     a       b       c       d
$cat tst.awk
开始{
FS=OFS=“\t”
查找=ARGV[--ARGC]
删除ARGV[ARGC]
}
{
找到=0
而(!found&((getline str0)){
拆分(str、arr)
如果($1==arr[3])&($2==arr[4])){
$0=$0 OFS arr[1]OFS arr[2]
发现=1
}
}
关闭(查找)
打印
}
$gawk-f tst.awk文件a文件b
chr1 123 aa b c d xxxx abcd
chr1 234 a b c d
chr1 345 aa b c d yyyy定义
chr1 456 a b c d
它使用几乎为零的内存,因为它不在内部存储任何值,但速度会很慢,因为对于fileA中的每一行,它会读取fileB中的每一行,直到找到匹配项,与您已经尝试的相反,您尝试从fileB读取所有行并将它们存储为由字段3和4键入的数组元素,在这种情况下,它将是fileA的每一行的内部哈希查找,而不是外部线性搜索

如果fileA中有许多键在fileB中不存在,那么可以通过在第3和第4个字段中对fileB进行排序,然后将getline循环中的测试更改为类似以下内容,从而大大提高速度:

        if ( ($1 FS $2) == (arr[3] FS arr[4]) ) {
            $0 = $0 OFS arr[1] OFS arr[2]
            found = 1
        }
        else (if ($1 FS $2) < (arr[3] FS arr[4]) ) {
            found = 1
        }
if($1 FS$2)==(arr[3]FS arr[4])){