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])){