我使用awk处理CSV数据文件。我的数据文件中有三个字段,例如文件a.txt。我希望awk从另一个文件b.txt中读取一个字段,然后如果第一列与读取的表达式匹配b.txt,则从我的a.txt中写入该行。我发现以下内容可以做我想做的事。
awk 'BEGIN {FS=","} { while(getline l < "b.txt") PATS[l] }ok=0;{for (p in PATS) if ($1 ~ p) ok=1}; ok {print $0}' < a.txt
然而,我遇到了巨大的内存泄漏,程序退出时出现内存错误。 a.txt约为41000行。如果有人能指出我的记忆力和/或提出替代解决方案,我将不胜感激。
答案 0 :(得分:5)
使用getline
验证这样的两个文件不是一个好主意,很可能是您的问题的根本原因。有getline
函数有很多注意事项,尽管它是一个很好的工具,但它经常被误用。
我建议使用awk
内置变量NR
和FNR
来扫描b.txt
文件并将其存储在数组中。加载数组后,如果$1
与数组的键匹配,则可以从a.txt
检查awk -F, 'NR==FNR{PATS[$0]++;next}$1 in PATS' b.txt a.txt
。
类似的东西:
NR
注意我在awk命令后放置了两个文件。这样做,直到FNR
和FNR
相同(对于第一个文件只相同,在第一个文件完成后,PATS
将重置为1)我们创建一个名为next
并使用整行作为关键字。 awk
阻止第二个b.txt
语句运行。完成a.txt
后,我们转移到$1
文件并查找1
在您的阵列中的存在。如果是,则评估为$1
并打印该行。如果您的数组中不存在~
,则它将评估为false并且不会打印该行。
上面的命令会查找完全匹配。我看到你使用了匹配运算符awk -F, 'NR==FNR{PATS[$0]++;next}{for(p in PATS) if($1~p) print $0}' b.txt a.txt
,这也意味着部分匹配。如果这就是你想要的,你可以做到:
{{1}}
如果这对您不起作用,我建议您从这两个文件中发布一些示例数据。
答案 1 :(得分:1)
如果你的shell是bash或ksh(或者zsh)
,这就是你想要的grep -f <(sed 's/^/^/; s/$/,/' b.txt) a.txt