比较两个UNIX文本文件,找出新增内容(diff和comm命令)

17 March 2011

最近项目中遇到一个奇怪的bug,仔细检查后发现是由一行简单代码引起的。这行代码要做的事情很简单:比较两个UNIX文本文件,找出并打印文本2比文本1新增加的内容。代码调用了diff命令,示例如下:

# temp1.txt文件内容
$> cat temp1.txt
20110224
20110225
20110228
20110301
20110302

# temp2.txt文件内容
$> cat temp2.txt
20110228
20110301
20110302

20110303
20110304

# diff命令输出结果
$> diff temp1.txt temp2.txt
1,2d0
< 20110224
< 20110225
5a4,5
> 20110303
> 20110304

# 只输出temp2.txt文件独有的内容
$> diff temp1.txt temp2.txt | grep "> " | sed 's/> //g'
20110303
20110304

可以看到,输出结果去掉了两个文件的共同内容,只输出了temp2.txt的新增部分,和预想的结果一样。

 

但是,随着temp1.txt文件内容的增加,diff命令出现了不同预期的结果:

$> cat temp1.txt
20101216
20101217
20101220
20101221
20101223
20101224
20101227
20101228
20101229
20101230
20101231
20110103
20110104
20110105
20110106
20110107
20110110
20110111
20110112
20110113
20110114
20110117
20110118
20110119
20110120
20110121
20110124
20110125
20110126
20110127
20110128
20110131
20110201
20110202
20110203
20110204
20110207
20110208
20110209
20110210
20110211
20110214
20110215
20110216
20110217
20110218
20110221
20110222
20110223
20110224
20110225
20110228
20110301
20110302
20110303

$> cat temp2.txt
20110228
20110301
20110302
20110303

20110304
20110307
20110308
20110309
20110310
20110311
20110314

$> diff temp1.txt temp2.txt
1,55c1,11
< 20101216
< 20101217
< 20101220
< 20101221
< 20101223
< 20101224
< 20101227
< 20101228
< 20101229
< 20101230
< 20101231
< 20110103
< 20110104
< 20110105
< 20110106
< 20110107
< 20110110
< 20110111
< 20110112
< 20110113
< 20110114
< 20110117
< 20110118
< 20110119
< 20110120
< 20110121
< 20110124
< 20110125
< 20110126
< 20110127
< 20110128
< 20110131
< 20110201
< 20110202
< 20110203
< 20110204
< 20110207
< 20110208
< 20110209
< 20110210
< 20110211
< 20110214
< 20110215
< 20110216
< 20110217
< 20110218
< 20110221
< 20110222
< 20110223
< 20110224
< 20110225
< 20110228
< 20110301
< 20110302
< 20110303

---
> 20110228
> 20110301
> 20110302
> 20110303

> 20110304
> 20110307
> 20110308
> 20110309
> 20110310
> 20110311
> 20110314

$> diff temp1.txt temp2.txt | grep "> " | sed 's/> //g'
20110228
20110301
20110302
20110303

20110304
20110307
20110308
20110309
20110310
20110311
20110314

可以看到,diff命令不但输出了temp2.txt文件的新增部分(20110304-20110314),也同时输出了两个文件的共同内容(20110228-20110303),从而导致了与预期不一致的结果。

查看diff命令的man手册发现,diff的作用是比较两个文件的内容,并输出两个文件之间的差异,产生一个能够将两个文件互相转换的列表,但这个列表并不能100%保证是最小集。于是,在上面的例子中,我们看到diff给出了temp1.txt和temp2.txt文件的比较差异结果,但其中包含了两个文件的共同部分,因此与预期不一样。

 

一个解决的方法是,可以用comm命令代替diff,示例如下:

$> comm -13 temp1.txt temp2.txt
20110304
20110307
20110308
20110309
20110310
20110311
20110314

comm命令用来比较两个文件,具体用法:

comm [-123] file1 file2
-1 过滤file1独有的内容
-2 过滤file2独有的内容
-3 过滤file1和file2重复的内容

 

PS,看了下diff的输出格式,主要有以下几种:

n1 a n3,n4
n1,n2 d n3
n1,n2 c n3,n4

例如"1,2d0" "5a4,5" "1,55c1,11"等。其中n1和n2指第一个文件的行数,n3和n4指第二个文件的行数。"a"代表add增加,"d"代表delete删除,"c"代表change整块变动。

有了diff的输出结果,可以使用patch命令将一个文件恢复成另一个,例如:

$> cat temp1.txt
20110224
20110225
20110228
20110301
20110302

$> cat temp2.txt
20110228
20110301
20110302
20110303
20110304

$> diff temp1.txt temp2.txt > temp.diff

$> cat temp.diff
1,2d0
< 20110224
< 20110225
5a4,5
> 20110303
> 20110304

# 使用temp.diff和temp1.txt恢复temp2文件
$> patch -i temp.diff -o temp2_restore.txt temp1.txt
Looks like a normal diff.
done

# 完成后temp2_restore和原temp2文件内容一致
$> cat temp2_restore.txt
20110228
20110301
20110302
20110303
20110304


下一篇: 使用wget下载数据文件 →

blog comments powered by Disqus