如何根据列比较 unix 中的两个文件
Posted
技术标签:
【中文标题】如何根据列比较 unix 中的两个文件【英文标题】:How do I compare two files in unix based on their columns 【发布时间】:2020-10-26 10:27:16 【问题描述】:我对 unix 命令相当陌生,但我有两个 .csv 文件,我想将第一列与 diff 或 comm 进行比较。每一行都是不同的,如果我要比较整行,这就是为什么我想比较每个文件中的第一列,然后以数字形式打印出差异,其中土地代码不应被多次计算。第一个文件还有一个我想在比较时跳过的标题。
来自 file1 的样本:
iso_code,continent,location,date,total_cases
AND,Denver ,America,2020-07-26,897.0
ABW,Copenhagen Denmark,,2020-03-13,2.0
AFG,Oslo,Norway,2020-09-06,324.0
AZE,Hamburg,Germany,2020-03-30,29.0
来自 file2 的样本:
AND,Denver ,America,2020-07-26,897.0
ABW,Copenhagen Denmark,,2020-03-13,5.0
ABW,Chil Ukrain,Aruba,2020-10-06,4449.0
ALB,Upsala,Sweden,2020-08-275.0,
AFG,Afghanistan,,2020-09-06,324.0
预期的输出应该是“2”,因为在两个文件中出现了两次相同的土地代码。国家代码的重复只能计算一次。这就是为什么预期输出应该是 2 而不是 3
我尝试了多种解决方案:
awk 'NR==FNRc[$1]++;next;c[$1] == 0' owid-covid-data-filtered.csv owid-covid-data.csv | wc -l
使用 awk 我得到输出:1
和
diff owid-covid-data.csv owid-covid-data-filtered.csv |cut -d' ' -f1 owid-covid-data-filtered.csv| wc -l
总的来说,我希望在 file1 和 file2 第 1 列中出现相似的情况
【问题讨论】:
这些解决方案提供了什么输出,为什么会出错? @underscore_d 我的输出是 51798,这是文件中的所有行。结果应该接近 200 左右。 请在您的问题中澄清:预期输出 2 是否因为 file2 中有两个代码在 file1 中不存在? 您的awk ... | wc -l
如您所料返回 2.. 有什么问题?你问的是什么问题?
@JamesBrown 抱歉忘了提,使用 awk 我得到“awk:无法打开文件”
【参考方案1】:
根据问题的awk
脚本中的条件c[$1] == 0
,我假设您要打印file2
中包含file1
中不存在的代码的行。
正如现在澄清的那样,您想要计算两个文件中存在的代码,请参阅答案末尾的下方进行反向检查。
对脚本稍作修改即可解决问题:
awk -F, 'NR==FNR if(NR!=1)c[$1]++; next c[$1]++ == 0' file1 file2
选项-F ,
指定逗号(,
)作为字段分隔符。
条件if(NR!=1)c[$1]++;
跳过file1
中的标题行。
c[$1]++ == 0
中的后增量运算符将使条件在 file2
中第二次或更晚出现相同代码时失败。
我在这里省略了结尾的| wc -l
以显示输出行。
我修改了file2
,使其在第 1 列中包含两行代码相同的代码,而 file1
中没有。
此处显示file2
AND,Europe,Andorra,2020-07-26,897.0
ABW,North America,Aruba,2020-03-13,2.0
ABW,North America,Aruba,2020-10-06,4079.0
ALB,Europe,Albania,2020-08-23,8275.1
ALB,Europe,Albania,2020-08-23,8275.2
AFG,Asia,Afghanistan,2020-09-06,38324.0
AFG,Asia,Afghanistan,2020-09-06,38324.0
和file1
从我得到这个输出的问题:
AND,Europe,Andorra,2020-07-26,897.0
ALB,Europe,Albania,2020-08-23,8275.1
(只打印带有ALB
的第一行`。)
您也可以在awk
中实现计数,而不是使用wc -l
。
awk -F , 'NR==FNR if(NR!=1)c[$1]++; next c[$1]++ == 0 count++ END print count' file1 file2
如果您想打印来自file2
的行,其中包含file1
中存在的代码,可以像这样修改脚本:
awk -F, 'NR==FNR if(NR!=1)c[$1]++; next c[$1] c[$1]=0; print' file1 file2
打印出来
ABW,North America,Aruba,2020-03-13,2.0
AFG,Asia,Afghanistan,2020-09-06,38324.0
(第一行代码ABW
。)
评论中要求的替代解决方案。
tail -n +2 file1|cut -f1 -d,|sort -u>code1
cut -f1 -d, file2|sort -u>code2
fgrep -vf code1 code2
rm code1 code2
或者在不使用临时文件code1
和code2
的情况下组合在一个命令中:
fgrep -f <(tail -n +2 file1|cut -f1 -d,|sort -u) <(cut -f1 -d, file2|sort -u)
添加| wc -l
来计算行数而不是打印它们。
解释:
tail -n +2
打印从第二行开始的所有内容cut -f1 -d,
打印第一个字段,以,
分隔sort -u
对行进行排序并删除重复项fgrep -f code1 code2
打印所有行code2
包含来自 code1
的任何字符串
【讨论】:
出于纯粹的好奇和学习,还有没有办法用 grep 或 comm 做到这一点?【参考方案2】:在 file1 和 file2 第 1 列中的出现相似:
$ awk -F, 'NR==FNRa[$1];next$1 in a' file1 file2
输出:
ABW,North America,Aruba,2020-03-13,2.0
ABW,North America,Aruba,2020-10-06,4079.0
AFG,Asia,Afghanistan,2020-09-06,38324.0
【讨论】:
以上是关于如何根据列比较 unix 中的两个文件的主要内容,如果未能解决你的问题,请参考以下文章
如何比较两个表的列并将值插入到基于 SQL Server 中存储过程中的比较的新表中