我有一个包含串联电子邮件的文件,如下所示:
id emails
1 [email protected]
2 [email protected]
3 [email protected],[email protected],[email protected]
每行只有不同的电子邮件,但从一行到另一行可能有重复项,如上面第 1 行和第 3 行所示。我需要从文件中删除重复项,以便文件如下所示:
id emails
1 [email protected]
2 [email protected]
3 [email protected],[email protected]
这意味着我需要检查每一行及其后面的所有行。考虑到我拥有的数据量,这对于任何类型的迭代脚本都是不可行的。我觉得有一种简单(或至少可行)的方法可以实现这一点awk或者sed但我还没有找到。
答案1
这是一个 sed 解决方案,适用于您的确切输入格式,并且希望运行速度也很快。
sed -rz 's:[ \t]+:,:g;s:$:,:mg;:l;s:,([^,]+),(.*),\1,:,\1,\2,:;tl;s:,$::mg;s:^([^,]+),:\1\t:mg' file.csv
怎么运行的:
“-z”标志加载整个文件,因此以下代码仅应用一次,而不是像默认情况那样应用到每一行。
#transform input format to actual CSV format
s:[ \t]+:,:g;s:$:,:mg;
#loop while the s command can still find and replace
:l;
#main code: find two identical cell values anywhere and delete the latter
#on a very big file this can suffer from backtracking nightmare
s:,([^,]+),(.*),\1,:,\1,\2,:;
tl;
#transform format back
s:,$::mg;s:^([^,]+),:\1\t:mg
答案2
如果您的文件是真正的 csv 文件(simple-csv),如下所示,您可以使用以下awk
命令:
输入:
[email protected]
[email protected]
[email protected],[email protected],[email protected]
命令:
awk -F, '{ COMMA="";i=0; while (++i<=NF) {
$1=$i; printf (!seen[$1]++)?COMMA$i:""; COMMA=","}; print ""
}' infile.csv
输出:
[email protected]
[email protected]
[email protected],[email protected]
如果没有,并且输入就像您问题中给出的那样,您可以使用以下内容:
awk 'NR==1; NR>1{id=$1"\t"; COMMA=$1="";split($0, ar, /,| /);
for(i in ar){if(ar[i]!=""){printf(!seen[ar[i]]++)?id""COMMA""ar[i]:""; COMMA=",";id=""}
} print ""}' infile
输出:
id emails
1 [email protected]
2 [email protected]
3 [email protected],[email protected]