如何根据列比较 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

或者在不使用临时文件code1code2的情况下组合在一个命令中:

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 中的两个文件的主要内容,如果未能解决你的问题,请参考以下文章

如何根据2列比较PySpark中的2个数据帧?

根据列内的值比较两个数据框

如何比较两个表的列并将值插入到基于 SQL Server 中存储过程中的比较的新表中

根据第一列比较两个文件,打印一个文件的唯一部分

在UNIX shell编程里如何比较两个文件哪个修改的时间晚些!急谢谢!

如何将 Unix 纪元时间戳与 SQL 中的 DATE 进行比较?