Linux中的Diff和Patch

本文主要记录两个命令的学习情况:diff 和 patch。diff 和 patch 是一对工具,使用这对工具可以获取更新文件与历史文件的差异,并将更新应用到历史文件上。在数学上说,diff就是对两个集合的差运算,patch就是对两个集合的和运算。

简单的例子

使用这个例子来说明如何进行文件的对比和打补丁。

这里有两个文件 original.txt 和 updated.txt,如下:

#include <stdio.h>

function old(){
        printf("This is a file\n");

        return 0;
}
#include stdio.h

function new(){
        printf("This is b file\n");
        return 0;
}

执行 diff original.txt updated.txt的结果为

下面先对结果中出现的一些符号做一些解释。1,4c1,这个内容输出实际上是给patch看的,表示告诉patch在original.txt文件中的1到4行应当被updated.txt中的内容替换,替换的内容是updated.txt的第1行。这里可能会出现三个字母表示不同的意义,分别是c表示更新、a表示追加、d表示删除。

c表示在original文件中的m,n行的内容将要被updated文件中的内容替换。
a表示追加,这时左边的数字只能是一个数字,而不会是一个范围,表示向original文件中追加右侧数字表示内容。
d表示删除。左侧的数字可能是一个范围,表示要删除的内容,右侧是一个数字,表示如果没有被删除应该出现在updated文件的什么位置。也许有人觉得后边的数字是多余的,保留这个数字是因为补丁可以反向使用。
<表示patch应当将这个标志后面的内容删除。
>表示patch应当将这个标志后面的内容添加。

了解了diff的输出结果,该给original文件创建补丁了。补丁实际上就是diff的输出结果,我们可以直接将输出结果保存成文件,也可以使用管道符号做这件事,如下:

diff original.txt updated.txt > mypatch.patch

这时我们就有了一个补丁文件,可以将original文件更新了updated文件了。

patch original.txt -i my patch.patch -o updated-1.txt

这个命令会生成一个新的文件,可以看到这个我们之前的update.txtw文件一模一样。

上下文补丁

观察之前diff给出的结果样式,对于需要替换的位置,仅仅给出了行号,如果文件突然新增了一个空行,补丁应用的时候就会发生问题。另外一种情况,如果将补丁文件应用到了一个错误的源文件上,假如恰好这个文件有同样的行数,那么补丁也可以成功应用。而这都是我们不希望看到的结果。幸好,diff提供了一种不同的结果样式来避免上面的这些问题。

diff -c original.txt updated.txt

比较结果中包含了文件名,这样我们在应用补丁的时候,就不用输入文件名,从而节省了时间,避免了文件名输入错误的可能。文件名后都跟着文件的修改时间。再往下就是15个星号 * 表示后面的内容为文件替换、更新、删除等。*-包含的数字或者数字范围表示行号,!开始的内容表示需要替换的内容,-表示需要删除的内容,表示需要增加的内容,patch会依据这个上下文关系对文件进行更新。

patch -i mypatch2.patch -o updated.txt

注意,这里如果不指定输出文件的话,源文件就会被更新(这本来就是补丁文件的作用)。通常我们都会对源文件应用补丁,通常需要对多个文件进行处理。

比较多个文件并应用补丁

比较多个文件最简单的办法就是直接在命令后面跟文件夹,例如,如果包含子文件夹,记得加上 -r 参数。

diff originaldirectory updateddirectory 

也可以看看上下文比较的结果

RousseaudeMacBook-Pro:diff rousseau$ diff -c original update
diff -c original/function.txt update/function.txt
*** original/function.txt     Fri Feb 17 09:41:26 2017
--- update/function.txt     Fri Feb 17 09:42:06 2017
***************
*** 1,5 ****
! #includ <stdio.h>

  function main(){
       return 1;
  }
--- 1,8 ----
! #include <stdio.h>
! #include <stdlib.h>

  function main(){
+      printf("This is function main\n");
+
       return 1;
  }
diff -c original/original.txt update/original.txt
*** original/original.txt     Fri Feb 17 09:40:29 2017
--- update/original.txt     Fri Feb 17 09:40:51 2017
***************
*** 1,9 ****
  #include <stdio.h>

! function old(){
!      printf("This is a file\n");

       return 0;
  }

- void 0;
--- 1,8 ----
  #include <stdio.h>

! function newd(){
!      printf("This is a new file\n");

       return 0;
  }

下面来看看怎么对多个文件应用补丁,首先生成一个补丁文件,我们还是用上下文的格式。diff -c original update > directory.patch

在一个新的目录下拷贝 original 文件夹和补丁文件,执行 patch -i directory.patch,此时会提示找不到文件,因为patch会在当前文件夹查找文件(默认情况下patch会将文件名前的所有文件夹去掉)因为此时补丁文件在文件夹外面,所以我们应当告诉patch不要这么做,使用-p参数。

patch -p0 -i directory.patch

也许有人会问,如果我把补丁文件移动到文件夹中进行打补丁操作不就可以了嘛,注意千万不要这么做。如果文件夹中还有子文件夹,那么patch不会到子文件夹中寻找文件,这样就会对结果产生影响,特别是在不同文件夹中有相同名字的文件的时候。

还原补丁文件的操作

有时候版本需要进行回撤,这时可以使用 -R 参数。

patch -p0 -R -i directory.patch

Unified Format

GNU的diff和patch还提供了一种格式,称为 the unified format。这个格式更加精简,与上下文格式类似。但是不再将源文件和更新文件分开,而是组合在一起。并且没有特殊的替换标志,只有-+

diff -u original update

写在最后

对文本文件进行patch操作时,提前备份是一个好习惯,这可以避免你在弄错的情况下,面临一堆无法恢复的文件发愁。

参考资料:
1、Using Diff and patch
2、Diff比较两个文件夹
3、GNU Diff and patch

时间: 2024-07-30 21:34:53

Linux中的Diff和Patch的相关文章

Linux中patch命令的使用

下面我们来揭示一下Linux中patch命令的使用技巧. 语法是patch [options] [originalfile] [patchfile] 例如: patch -p[num] <patchfile -p参数决定了是否使用读出的源文件名的前缀目录信息,不提供-p参数,则忽略所有目录信息,-p0(或者-p 0)表示使用全部的路径信息,-p1将忽略第一个"/"以前的目录,依此类推.如/usr/src/linux-2.4.16/Makefile 这样的文件名,在提供-p3 参数

diff and patch

 转两篇diff和patch的文章, 打补丁相关.第一篇 :  情景一:你正尝试从代码编译一个软件包,发现有人已经对代码进行了小小的修改以便在你的系统上编译.他们通过补丁的方式发布自己的成果,但是你却不知道该如何使用它.答案是你使用一个叫做patch(很贴切)的命令行工具将补丁应用到原始代码上.  情景二:你下载了一个开源软件包的代码,花了一个小时左右稍作修改,成功的让它在你的系统上编译通过.你想把自己的成果分享给其他程序员,或者给软件包的作者.现在你就需要创建自己的补丁,你需要的工具是diff

Linux中查找当前目录下文件并更改扩展名

Linux中查找当前目录下文件并更改扩展名? 更改所有.gz文件为.aa# find ./ -http://www.aliyun.com/zixun/aggregation/11696.html">name "*.gz" -exec rename .gz .aa '{}' \; 示例: 执行命令之前的结果 [root@localhost software]# ll 总用量 84692  -rw-r--r--. 1 root root 13587692 6月  19 16

linux中PHP dirname(

  在php 中dirname() 函数返回路径中的目录部分,__FILE__而当前运行文件的完整路径和文件名.如果用在被包含文件中,则返回被包含的文件名.这是一个魔法变量(预定义常量),在windows中没有问题但在linux中路径出现的问题,下面我们一起来看看路径问题解决方法. 近期在给wordpress开发模板功能时发现,直接使用include("文件名")的形式调用其他php代码片段时会出现路径错误.之前服务器环境一直都是iis,未曾出现过类似的BUG,但换成linux服务器后

linux中的&amp;quot;瑞士军刀&amp;quot;

linux中的"瑞士军刀" busybox 俗称linux中的瑞士军刀,它类似于linux系统中bash 的一个缩微版,常用于嵌入式设备中,例如你的android手机中等等.busybox作为一个开源的应用,它的解析命令行的应用是值得学习的 http://busybox.net/

Linux中让显示器不休眠?

Linux中让显示器不休眠? 我们可以使用setterm命令: 操作如下: setterm -blank 0setterm -blank n (n为等待时间) setterm命令的其它选项: setterm: Argument error, usage setterm&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; [ -term terminal_name ]  [ -reset ]  [ -initialize

Linux中如何运行多个X窗口?

Linux中如何运行多个X窗口? startx默认以display :0.0起第一个X,通过传递参数给Xserver可以起多个X: # startx -- :1.0# startx -- :2.0... 然后用Ctrl-Alt-F7/F8...切换

linux 中配置apache 网站 编码设置为gb2312 浏览乱码

问题描述 linux 中配置apache 网站 编码设置为gb2312 浏览乱码 httpd.conf 添加了 AddDefaultCharset GB2312? 网页添加了 浏览器浏览的时候默认编码格式还是utf-8 显示乱码 解决方案 将环境变量LANG设置LANG="zh_CN GBK"

Linux中提示No such file or directory解决方法

  问题描述 解决方法 分析原因,可能因为我平台迁移碰到权限问题我们来进行权限转换 1)在Windows下转换: 利用一些编辑器如UltraEdit或EditPlus等工具先将脚本编码转换,再放到Linux中执行.转换方式如下(UltraEdit):File-->Conversions-->DOS->UNIX即可. 2)方法 用vim打开该sh文件,输入: [plain] :set ff 回车,显示fileformat=dos,重新设置下文件格式: [plain] :set ff=uni