Unix 性能改进 - 可能正在使用 AWK

  • 本文关键字:AWK 性能 Unix unix awk
  • 更新时间 :
  • 英文 :


我有两个文件File1.txt(它有6列由管道分隔(和File2.txt(它有2列由管道分隔(

文件1.txt

NEW|abcd|1234|10000000|Hello|New_value|
NEW|abcd|1234|20000000|Hello|New_value|
NEW|xyzq|5678|30000000|myname|New_Value|

文件2.txt

10000000|10000001>10000002>10000003>10000004
19000000|10000000>10000001>10000002>10000003>10000004
17000000|10000099>10000000>10000001>10000002>10000003>10000004
20000000|10000001>10000002>10000003>10000004>30000000
29000000|20000000>10000001>10000002>10000003>10000004

目标是对于 File1.txt 中的每一行,我必须选取第 4 列,并且必须在 File2.txt 中搜索该值。如果在 File2.txt 中找到任何匹配项,那么我必须从 File2.txt 中选取所有行,但仅选取第一列。

这可能会在目标文件中生成更多数量的记录。输出应如下所示(其中最后一列 123 来自固定变量(

NEW|abcd|1234|10000000|Hello|New_value|123    (this row comes as it matches 1st row & 4th column of File1.txt with 1st row of File2.txt)
NEW|abcd|1234|19000000|Hello|New_value|123    (this row comes as it matches 1st row & 4th column of File1.txt with 2nd row of File2.txt)
NEW|abcd|1234|17000000|Hello|New_value|123    (this row comes as it matches 1st row & 4th column of File1.txt with 3rd row of File2.txt)
NEW|abcd|1234|20000000|Hello|New_value|123    (this row comes as it matches 2nd row & 4th column of File1.txt with 4th row of File2.txt)
NEW|abcd|1234|29000000|Hello|New_value|123    (this row comes as it matches 2nd row & 4th column of File1.txt with 5th row of File2.txt)
NEW|xyzq|5678|20000000|myname|New_Value|123   (this row comes as it matches 3rd row & 4th column of File1.txt with 4th row of File2.txt)

我可以写一个像下面这样的解决方案,它也给了我正确的输出。 但是当 File1.txt 和 File2.txt 都有大约 150K 行时,这个需要 21 分钟的奇数。生成的最终目标文件中有超过 1000 万行。

VAL1=123
for ROW in `cat File1.txt`
do
Fld1=`echo $ROW | cut -d'|' -f'1-3'`
Fld2=`echo $ROW | cut -d'|' -f4`
Fld3=`echo $ROW | cut -d'|' -f'5-6'`
grep -i $Fld2 File2.txt | cut -d'|' -f1  > File3.txt
sed 's/^/'$Fld1'|/g' File3.txt | sed 's/$/|'${Fld3}'|'${VAL1}'/g' >> Target.txt
done 

但我的问题是这个解决方案可以优化吗?可以使用AWK或任何其他方法重写以更快地完成吗?

我很确定这会更快(因为在单个 awk 或 sed 进程中使用隐式循环通常(如果不是总是比在 shell 循环中一遍又一遍地调用它更快(,但您必须尝试一下并让我们知道:

编辑:此版本应该解决输出中重复项的问题

$ cat a.awk
NR == FNR {
for (i=1; i<=NF; ++i) {
if ($i in a)
a[$i] = a[$i] "," $1
else
a[$i] = $1;
}
next 
}
$4 in a {
split(a[$4], b, ",")
for (i in b) {
if (!(b[i] in seen)) {
print $1, $2, $3, b[i], $5, $6, new_value
seen[b[i]]
}
}
delete seen
}

输出包含所需的行,尽管顺序不同:

$ awk -v new_value=123 -v OFS="|" -f a.awk FS='[|>]' file2.txt FS='|' file1.txt 
NEW|abcd|1234|19000000|Hello|New_value|123
NEW|abcd|1234|17000000|Hello|New_value|123
NEW|abcd|1234|10000000|Hello|New_value|123
NEW|abcd|1234|29000000|Hello|New_value|123
NEW|abcd|1234|20000000|Hello|New_value|123
NEW|xyzq|5678|20000000|myname|New_Value|123

我猜你的性能下降来自于反复将文件读入内存grepsedsed。如果您可以将File2的内容存储在内存中(甚至临时SQLite数据库中(,那么这应该可以加快速度。然后,您将逐行处理 File1,并且只需对 File2 键进行简单的查找。

在运行脚本时运行htop或某些活动监视器以跟踪 RAM 和 CPU 使用率会很有帮助。

一个稍微优化的 gnu awk 脚本:

awk 'NR==FNR{a[$4]=$0;next}
{
for(i=1; i<=NF; i++){
if($i in a) 
print gensub("[^|]+\|",$1 "|",4,a[$i])
}
}' FS='|' file1 FS='[|>]' file2

第一条语句用 file1 的内容填充数组a

第二个块语句遍历 file2 的所有字段,并打印与 file2 的第一个字段匹配的数组内容。

打印的字符串使用 awkgensub函数进行修改。它只允许更改找到的第 4 个模式。

最新更新