在 linux 中使用 awk 比较两个文件

Posted

技术标签:

【中文标题】在 linux 中使用 awk 比较两个文件【英文标题】:Comparing two files using Awk in linux 【发布时间】:2015-04-14 13:16:31 【问题描述】:

我有两个文件,文件A和文件B。文件A的结构如下图所示:

3314530275|76|1|20240422045006|
3335984469|64|2|20150804235959|
3367892381|203|3|20141025235959|
3369039388|203|4|20131219235959|

第二个文件B的内容如下:

3314530275|2000|999000000073101614|0|20370101000000|76|
3314530275|2000|999000000073101614|0|20370101000000|76|
3369039388|2000|812000002628721|-112|20360101235959|203|
3335984469|5037|5210367877660|180|20150213000000|64|
3335984469|5048|5210367877661|6|20150213000000|64|
3335984469|2000|812000002629182|1913|20360101235959|64|
3367892381|5014|5210365185964|419430400|20150308000000|203|
3367892381|5044|5210365185965|226020|20150308000000|203|
3367892381|2000|817000102009605|0|20360101235959|203|

脚本应该首先检查文件A,如果第三个字段($3)等于2,它应该存储第一列($1)和第四列($4)的值。

之后它将检查我们在第一步中存储的值中是否存在(第二个文件的)$1 值。

    如果值存在并且第二个字段等于 2000,它应该打印 $1,$2,$4,(我们从第一个文件中获取并存储它的第四列的值)

    如果值存在且第二个字段不等于 2000,则应打印 $1,$2,$4,$5

上述案例中的示例输出:

3335984469|5037|180|20150213000000|
3335984469|5048|6|20150213000000|
3335984469|2000|1913|20150804235959|

这是我目前所拥有的:

awk -F \| 'FNR==NR if($3 == 2) a[$1] = $4; next ($1 in a) if($2==2000) print$1"|"$2"|"$4"|"a[$1]"|" ($1 in a) if($2!=2000) print$1"|"$2"|"$4"|"$5"|" ' FileA FileB > Output_File

任何帮助将不胜感激。

【问题讨论】:

到目前为止你有什么收获? 我现在已经想出了这个,但我不确定是否正确使用代码,因为输出似乎缺少很多应该存在的值-------- ------- awk -F \| 'FNR==NR if($3 == 2) a[$1] = $4;下一个 ($1 in a) if($2==2000) print$1"|"$2"|"$4"|"a[$1]"|" ($1 in a) if($2!=2000) print $1"|"$2"|"$4"|"$5"|" ' FileA FileB > Output_File 我正在寻找的是实现相同目标的另一种方法!我的脚本适用于值样本,但是当我在大文件上使用它时,结果不一样 它看起来应该可以工作,除非你在文件 A 中有重复的 $1。你在文件 A 中有重复的第一个字段吗? @MuhammadAbdullah,看起来不错。我要做的唯一更改是将ifelse 折叠到同一个块中:$1 in a if ($2 == 2000) print $1,$2,$4,a[$1],""; else print $1,$2,$4,$5,""——暗示OFS="|" 【参考方案1】:
awk  'BEGINFS=OFS="|";FNR==NRif($3==2)a[$1]=$4;next;if( $1 in a && $2==2000 )print $1,$2,$4,a[$1]else if ($1 in a && $2!=2000)print $1,$2,$4,$5' 'fileA'  'fileB'

我对您的命令行进行了调整以获取上面的命令行

if( $1 in a && $2==2000 )print $1,$2,$4,a[$1]

else if ($1 in a && $2!=2000)print $1,$2,$4,$5

结果

3335984469|5037|180|20150213000000
3335984469|5048|6|20150213000000
3335984469|2000|1913|20150804235959

【讨论】:

这也可以,但是很抱歉@Xorg,我只能选择一个作为正确答案! :(【参考方案2】:

如果文件A 的内容正确(文件A 中的335984469 应该是3335984469,即多一个前导3。),您的脚本将按原样运行,但它可以简化为:

$ cat tst.awk
BEGIN FS=OFS="|" 
FNR==NR  if ($3==2) a[$1] = $4; next 
$1 in a  print $1, $2, $4, ($2==200 ? a[$1] : $5), "" 

$ awk -f tst.awk fileA fileB
3335984469|5037|180|20150213000000|
3335984469|5048|6|20150213000000|
3335984469|2000|1913|20360101235959|

如果您觉得有用,请随意将其全部塞回一行。

如果上述方法不起作用,请检查两个输入文件中是否存在控制字符,最有可能是 Microsoft 在其工具创建文件时慷慨捐赠的 control_Ms。您可以使用cat -v 来检查它们,并使用dos2unix 或类似的方式将它们删除。

【讨论】:

感谢埃德莫顿。正如您所指出的,文件 A 中有一个错字。我纠正了我的错误。你能解释一下($2==2000 ? a[$1] : $5)这部分代码是如何工作的吗? 如果$2==2000为真,则返回值a[$1],否则返回值$5 @tripleee 是正确的,它只是一个三元表达式,许多语言共有 - 谷歌“三元表达式”。 感谢@tripleee 和 Ed Morton!

以上是关于在 linux 中使用 awk 比较两个文件的主要内容,如果未能解决你的问题,请参考以下文章

linux 两个大数据量的文件如何比较

使用 awk 比较两个文件

使用 awk 比较两个文件并打印不匹配的记录

比较awk中两个文件的字段

awk将同一行中的两个元素与正则表达式进行比较

AWK 比较两个文件中的两列输出匹配行 - 匹配中缺少行