Linux上diff命令详解
diff程序是linux上非常重要的工具,用于比较文件的内容,特别是比较两个版本不同的文件(本文中的a.c、b.c可以理解为两个版本的同一个文件,b.c是在a.c的基础上的修正版)以找到改动的地方。diff在命令行中打印每一个行的改动。最新版本的diff还支持二进制文件。diff程序的输出被称为补丁(patch),因为unix系统中还有一个patch程序,可以根据diff的输出将a.c的文件内容更新为b.c。diff是svn、cvs、git等版本控制工具不可或缺的一部分。
diff和patch实例
下面用一个实例来讲述diff和patch的使用。
文件a.c的内容如下:
1 |
|
文件b.c的内容如下:
1 |
|
执行命令:
1 | diff a.c b.c > b.patch |
输出b.patch的内容如下:
5c5
< // add code here
---
printf("Hello world");
接着执行下面的命令就可以将patch文件b.patch应用于a.c文件上,将a.c文件的内容更新为新的版本(即b.c)
1 | patch a.c b.patch |
a.c的内容被更新为b.c的内容:
1 |
|
不过,diff的输出让人读起来很废劲,因为这个输出本来就不是给人看的,如果你知道一点关于ed编辑器的用法,就容易理解了。最开始的时候diff的输出不是这种格式的,后来受到ed编辑器的影响才变成这个样子,至于其发展历程请移步维基百科,因此在解释diff的输出之前,先简单介绍一下ed编辑器。
ed编辑器
ed是一个交互式的文本编辑器,类Unix系统中有很多很神奇的编辑器,号称神器的有vi、vim、emacs,还有常规意义的编辑器nano、gedit,还有看起来很诡异的sed(Stream Editor)、awk,ed这是另一个很诡异的编辑器,不同于前面的任何一种。
打开shell,按次序输入如下的命令(需要一句一句的敲):
touch c.c
ed c.c
0a
#include <stdio.h>
int main(int argc, char *argv[])
{
// add code here
return 0;
}
.
w
q
使用cat命令查看c.c,该文件的内容就是上面代码中“0a”和“.”之前代码。
和vim一样,ed通过一系列的命令来编辑文件:
- “ed c.c”表示用ed对文件c.c进行编辑
- “0a”表示在第0行后进行添加(a表示add,同样,d表示删除,c表示修改)
- 接着输入需要添加的内容,输入完成后换一行,输入“.
”( 表示回车),表示输入完成 - 输入“w
”表示保存文件 - 输入“q
”表示退出编辑器
ed编辑器的好处在于可以将一系列命令写成一个文件,然后进行批量执行。比如需要在所有的源代码开头加上版权信息,则可以编写如下的ed文件,保存为add_header:
0a
/**
* © 2012 zhlwish.com
*/
.
w
q
然后写一段shell脚本对源代码文件进行遍历,对每个代码执行如下代码即可批量对源代码文件添加版权信息:
1 | ed a.c < add_header |
关于ed的命令和其他方法请参考Unix ed Editor Command Set本文不详述。
diff的输出
diff的输出格式是对ed脚本(ed script)的一种扩展,遵循ed的命令语法,添加了”<”和”>”分别用于表示新文件的内容和旧文件的内容,比如前文中diff的输出可以按如下方式理解:
- “5c5”表示a.c的第5行有改动(change),改动后为b.c的第5行
- “< // add code here”表示a.c的第5行的内容
- “— ”是分隔符
- “> printf(“Hello world”);”表示b.c文件的第5行的内容
当然还有更复杂的情况,如“3c3,6”、“6d8”,前者表示旧版本文件中的第3行被修改,对应新文件中的第3-6行,后者表示旧版本文件的第6行被删除,在新文件中是第8行。
可以通过参数指定diff输出格式,有兴趣的笔者可以分别进行尝试:
- -e –ed 输出为ed命令格式
- -n –rcs 输出为rcs命令格式
- -y 输出为两列对照模式
- -c 输出为上下文模式
diff的选项
除以上选项外,diff的有用的选项还包括:
- -r:当diff的参数为文件夹时,diff会遍历整个文件夹对新旧文件夹下同名的文件进行比较
- -w:忽略所有空格和制表符,将所有其他空白字符串视为一致。例如,if ( a == b ) 与 if(a==b) 相等。
- -i:忽略字母大小写。例如,小写 a 被认为同大写 A 一样。
因为成文仓促,不免有不对之处,敬请读者指正。(全文完)