`
anders0913
  • 浏览: 90810 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论
阅读更多
简介

   本文的目的是向Linux新手介绍一种无价的资源,Larry Wall的patch程序。patch是用来查找文件之间差异的GNU diff命令的一个接口;diff有很多选项,但是该命令最常用的用途是用来生成一个文件,该文件中列出了内容发生改变的行,显示两个原始文件、修改过的行以及由于内容没有变化而忽略掉的行。patch典型地用于把一个目录下的源代码文件更新到新的版本,从而就避免了下载整个新的源代码档案的必要。下载一个有效的patch仅仅需要下载发生变化的那些代码行就可以了。

   patch最初源自十年前,那时网络带宽的限制促进了patch的发展,然而和当时的很多Unix工具一样,直到现在,patch还在广泛应用。在Dr. Dobb之旅的2月份的程序员杂志中,Larry Wall对早期的patch做了一些很有趣的说明:

   DDJ:顺便问一下,patch和diff哪个出现的早?

   LW:从很长一段时间来说,diff出现地比较早。我想diff大约比patch早10年出现,一回想起来,我就纳闷为什么没有人早些想到使用patch呢?

   但是我想我知道这中间的原因。这很大程度上是心理因素使然。当开发出diff时,程序员增加了一个e选项,我想就是这个选项的原因,该选项后来滋生为一个ed脚本,因此大家都会对自己说,"嗯,如果我想自动使用diff,那么我就使用这个选项。"因此从来都没有人编写一个计算机程序来获取其它格式的输出并使用这些结果。或者是那些设计diff的人员,或者是那些使用diff格式而受益的人员太沉迷其中了,因为你可以对那些已经修改过的内容使用diff操作并让这些内容正常工作都是很容易的。

   现在回想起来,这个问题是显而易见的。但是平心而论,与其说这是一个天才的灵感的闪现,还不如说这是自信心的体现。我开发出rn的第一个版本,然后继续为它编写补丁,这整个事情就是一团乱麻。你不可能强制用户使用补丁,因为他们可以手工完成这些工作。因此,他们就会省略一些自己认为不必要的工作,他们把新的修改加诸于原来的程序之上,因此而使得程序混乱。我编写补丁,这样就没有人找借口说这很难了。

   我不清楚是否事实就是如此,但是多年以来,我一直对别人讲patch对于计算机文化的影响比rn和Perl的影响都要大。现在Internet的速度比原来有大幅度的提高,把整个发行版本分散到世界各地也变得更加简单,似乎只有在开发者之间才需要传送补丁。我已经很多年没有传送Perl的patch工具包了。我认为虽然patch整体上的重要性在逐渐降低,但是仍然是开发者交流思想的一种方法。但是就那一段时间而言,patch真正在相当大的程度上都影响了软件的开发方式。

   Larry Wall针对patch对于计算机业界总体上重要性正在降低的评价可能是正确的,但是在自由软件世界中,patch仍然是一种必不可少的工具。无处不在的patch使得新手和非程序员能够简单地参与软件的alpha测试和beta测试,这对于整个计算机业界是十分有益的。

   在我留意到在Linux内核邮件列表中会周期性的出现这样一件事情时就产生了写这篇文章的念头。大约每三个月就会有人张贴要求把Linux内核源代码的发行版本独立出来的文章,据说这是因为有些人只对i386的代码和IDE的磁盘驱动感兴趣,他们并不想为每个内核发行版本都下载Alpha、Sparc等等的文件和众多的SCSI驱动程序。这篇文章后面紧跟的是一些耐心的回复文章(有些文章则并没有耐心),大部分文章都是在讨论原来的使用有关patch来更新内核源代码。接着Linus Torvalds就会再次声明自己没有兴趣投身于这种把内核源程序切割成小块的繁杂的劳动,但是如果有人愿意,他们可以自由地开展这项独立的工程。到现在为止都没有志愿者出现。我并不想谴责那些内核黑客不能耐心等待,却把生活变得复杂;我猜想直接使用内核工作可能比检查整个内核的发行版本方案要更加有趣、更富有挑战性。下载11M的内核源程序包可是件非常耗费时间的事情(对于那些按照时间上网的人来说,这是很昂贵的),但是内核patch才只有几十K大小,很少会超过1M。我的硬盘上的2.1.99开发内核源程序经过patch的升级,已经升级到了2.1.119版本,我怀疑如果我紧随内核的发展而不断升级,那么也许我就要完整地下载每一个发行版本了。




   使用patch

   patch附带有一个很好的帮助,其中罗列了很多选项,但是99%的时间只要两个选项就能满足我们的需要:

   patch -p1 < [patchfile]

   patch -R < [patchfile] (used to undo a patch)

   -p1选项代表patchfile中文件名左边目录的层数,顶层目录在不同的机器上有所不同。要使用这个选项,就要把你的patch放在要被打补丁的目录下,然后在这个目录中运行path -p1 < [patchfile]。来自Linux内核patch的一个简短的引用可以这样实现:

   diff -u --recursive --new-file v2.1.118/linux/mm/swapfile.c linux/mm/swapfile. c--- v2.1.118/linux/mm/swapfile.c Wed Aug 26 11:37:45 1998 +++ linux/mm/swapfile.c Wed Aug 26 16:01:57 1998 @@ -489,7 +489,7 @@

   int swap_header_version;

   int lock_map_size = PAGE_SIZE;

   int nr_good_pages = 0; - char tmp_lock_map = 0; + unsigned long tmp_lock_map = 0;

   应用来自本段中使用-p1开关拷贝的patch可以有效地减短patch定位的路径;patch会查找当前目录下一个名为/mm的子目录,接着应该会在这儿发现swapfile.c文件,然后等待打补丁。在这个过程中,以破折号(“-”号,译者注)开始的行会被一个以加号(“+”号,译者注)开始的行代替。一个典型的patch会包含对多个文件的更新,每个部分中都由对两个版本的文件运行diff -u命令的输出结果组成。

   patch在操作时把自己的输出结果显示在屏幕上,但是这种输出通常都滚屏太快,来不及观看。原来准备patch的文件名为*.orig,新的patch文件会覆盖这个初始文件名。

   打补丁的问题

   使用不同版本的patch问题来源可能不同,所有的版本在网络上都是可用的。Larry Wall近年来已经不再做很多工作来更新patch了,这可能是由于他最后发行的一个版本在大部分情况下都能正常运行。最近几年以来,一直是GNU项目的FSF程序员发行新版本的patch。他们首先修订有问题的patch,但是我最近一直使用没有问题的2.5版本(这是Debian2.0的发行版本号)。过去,我的2.1版本也一直运行的很好。当前的GNU patch的版本可以从GNU FTP站点上获取,然而大部分人都只使用他们Linux发行版中所提供的版本。

   让我们假定你已经对一个目录下的源程序文件进行了patch修补工作,但是patch并没有清晰地发挥作用。这可能会偶然发生,在打补丁的过程中会显示错误信息,其中带有行号,说明哪一个文件出现了问题。有时错误是很明显的,例如缺少了分号,这种错误可以不费多大力气就能改正。另外一种可能是从patch部分删除了产生问题的部分,但是这样根据所涉及到的文件的不同可能会正常工作,也可能不能正常工作了。

   另外一种常见的错位为:假设你有一个未使用tar打包的内核源程序文件,在/linux/arch/下浏览各个子目录时你会发现各种机器体系结构子目录,例如alpah、sparc等等。如果你和大多数Linux用户一样,使用的是Intel的处理器(或者是Intel系列),你可以决定删除这些目录,这些目录对于编译你特殊的内核并不需要,只是白白占用了磁盘空间。一段时间之后发行了一个新的内核patch,此时试图进行patch操作,当它发现不能找到自己打补丁需要的Alpha或者PPC文件,就会停顿下来。幸运的是patch在这些地方允许用户参与,它会询问"Skip this patch?"回答"y",patch就可以按照正确的路径继续执行。也许你需要回答这个问题很多次,因此允许自己不需要的目录保留在磁盘上是一种很好的方法。

   给内核打补丁的技巧

   很多Linux用户使用patch都主要是给内核源程序打补丁,因此有一些技巧可以使用。可能最简单的方法是使用shell脚本给内核打补丁,这可以在内核源程序树中的/scripts子目录中找到。这种方便的、编写良好的脚本是由Nick Holloway在1995年编写的;两年以后,Adam Sulmicki增加了多种压缩格式的支持,包括*.bz、*.bz2、compress、gzip和无格式文本(也就是已经解压的patch)。这个脚本假定在你使用新版本的patch时,你的内核源程序是在/usr/src/linux目录中。这些缺省值可以通过这种格式的命令行开关覆盖:patch-kernel [sourcedir [patchdir] ]。如果任何一部分的patch失败,对内核打补丁的过程都会失败,但是如果patch清晰地起作用,它就会调用find,这会删除所有的patch留下的*.orig文件。

   如果你准备查看命令的输出,或者可能你希望保留*.orig文件直到你确定打过补丁的源程序编译已经通过,按照我的经验,直接运行patch(正如前面介绍的一样,patch位于内核源程序的最高目录)是很可靠的。为了避免对patch进行解压,在使用之前,可以使用这样一个技巧:

   gzip -cd patchXX.gz | patch -p1

   或者

   bzip2 -dc patchXX.bz2 | patch -p1

   在使用patch之后,可以使用find程序来检测被拒绝的文件:

   find . -name *.rej

   第一次使用这个命令,语法可能有些不清楚。点号(“.”)说明find应该查找当前目录并递规查找当前目录之下的所有子目录。记住,点号前后都应该有一个空格。通配符"*"号前面的反斜线把星号转义出来,以免shell会搞混,星号是有其它意义的。如果find找到了任何的*.rej文件,它就会把文件名打印到屏幕上。如果没有任何输出find就退出了,那么就差不多能确定patch正确发挥作用了。

   find的另外一个工作是删除*.orig文件:

   find . -name *.orig -print0 | xargs -0r rm -f

   这个命令敲起来相当麻烦,可以使用一个新的shell别名来代替这个命令。在你的~/.bashrc文件中类似这样的一行:

   alias findorig find . -name *.orig -print0 | xargs -0r rm -f

   可以允许你只输入findorig就可以调用前面的命令。如果别名命令的定义中包含空格,那么就必须使用单引号。为了不用先退出再重新登陆就可以使用一个新的别名,可以在命令行中敲如~/.bashrc。

   附加内容和结束语

   在撰写本文时,我刚好把自己的机器从2.1版本使用patch升级到了2.5版本。这两个版本都是来自现在的FSF/GNU维护人员。马上我就注意到2.5版本默认的输出已经改变了,屏幕上显示的信息变少了。原来在patch检测进行修补的行号时显示的Larry Wall的"...hmm"不见了。2.5版本的输出只剩下诸如"patching file [filename]"之类的信息了,而没有早期版本显示的那么多信息了。无可否认,信息滚屏太快,根本无法阅读,但是输出可以重定向到一个文件中供以后使用。这种变化不会影响程序的功能,但是减少了人为的成分。在我看来,使用诸如原来的"...hmm"信息和源代码中的注释一样,对于提醒用户程序是显示执行的工作的结果是很有价值的,这就像人在呼吸一样,而不应该使用一些毫无结果的位集合。通过对patch命令行增加--verbose开关可以恢复原来的显示内容,但是我相信很多用户既不会注意到这个选项,也不会不辞辛劳地输入这个选项。2.1和2.5版本的另外一个不同是除非patch给出了-b选项,否则不能创建*.orig备份文件。

   对于那些对软件和内核"前沿"bug报告测试和提供测试报告不感兴趣的人来说,patch并不是必须的,但是通常大部分Linux世界里有趣的开发都是属于这个范畴的。获得patch的使用方式并不困难,这种努力可以得到充分的回报。

   (译者注:由于水平有限,错误疏漏之处在所难免,如果你认为本文翻译的有问题,可以对其进行修改,请将修改后的文章给译者(xjtufr@263.net)发送一份。)

;-)

分享到:
评论

相关推荐

    C#实现Patch请求-demo

    相比于`PUT`方法需要提供完整的资源表示形式,`PATCH`允许客户端仅发送需要修改的部分数据,提高了效率并增强了灵活性。本文将通过一个具体的C#示例来探讨如何实现`PATCH`请求。 #### 二、核心知识点 ##### 2.1 `...

    draw9patch.zip

    9patch图片技术是Android原生提供的一种优化UI设计的方法,能够帮助开发者实现灵活、自适应的界面布局。在这个"draw9patch.zip"压缩包中,包含了一个名为"draw9patch"的工具,它可以帮助我们便捷地创建和编辑9patch...

    draw9patch

    本文将深入探讨Draw9Patch的原理、使用方法以及其在Android开发中的重要性。 一、Draw9Patch的基本概念 Draw9Patch,通常以`.9.png`为扩展名,是一种特殊的PNG图片,它包含了额外的边界信息,指示了图片哪些部分...

    patchmatch 算法细节

    总结来说,本文通过提出基于Patchmatch算法的图像补全新方法,通过全局迭代优化问题的构建,使用新的全局优化函数和算法求解思路,使得图像补全过程更加高效和自然。文章不仅详细介绍了相关技术的理论基础,还提供了...

    Linux命令学习手册-patch命令

    为了更好地理解`patch`命令的工作原理,我们通过一系列实例来说明其使用方法: **生成补丁文件** 假设我们有两个文件`test0`和`test1`,其中`test1`是对`test0`进行修改后的版本。我们可以使用`diff`命令来生成这...

    patch7.zip

    总结来说,"patch7.zip"是针对DevExpress与VS2017兼容问题的解决方案,通过"DevExpress.Patch.exe"补丁工具和"DevExpressPathVSP.vsix"扩展,开发者可以在VS2017环境中继续利用DevExpress的强大功能,提高开发效率。...

    Linux下patch打补丁命令实例详解.txt

    本文将深入探讨`patch`命令的用法及其在实际场景中的应用实例,帮助读者更好地理解和掌握这一关键技能。 #### patch命令语法 `patch`命令的基本语法如下: ```bash patch [选项] &lt;补丁文件名&gt; ``` 其中,`[选项]...

    详解如何使用git 生成patch 和打入patch

    本文将详细讲解如何使用Git生成patch文件以及如何将这些patch应用到项目中。 生成patch文件: 生成patch文件通常是为了提取某次或某系列提交的改动,以便于分享或审查。Git提供了`git format-patch`命令来完成这一...

    svn安装与patch文件应用

    - **生成Patch文件**: 使用 `TortoiseSVN` 的 `Export` 功能导出文件夹,然后使用 `Diff` 工具对比两个版本之间的差异。 - **应用Patch文件**: 使用 `TortoiseSVN` 的 `Apply Patch` 功能将差异应用到目标文件夹。 ...

    Python猴子补丁Monkey Patch用法实例解析

    Python中的猴子补丁(Monkey Patch)是一种编程技巧,允许在程序运行时动态修改或扩展已经定义的对象、类或模块的行为。这种技术常用于测试、调试和实现某些特殊功能,尤其是在不修改原始源代码的情况下。猴子补丁的...

    jquery.easyui.patch.js

    总结来说,jQuery EasyUI 的小数点输入问题主要是由于其内置的验证规则限制。通过创建`jquery.easyui.patch.js`这样的补丁文件,开发者可以自定义验证规则,从而解决这类问题。这种方法不仅适用于小数点输入,也可以...

    Linux下Patch的应用和制作方法介绍.docx

    总结来说,Linux下的`diff`和`patch`是开发者日常工作中不可或缺的工具,它们有效地提高了代码管理的效率,简化了版本间的差异处理。通过熟练掌握这两个工具的基本用法,可以轻松应对各种代码更新和维护任务。在实践...

    Android 9妹工具(9Patch).rar

    在Android开发中,9妹工具(9Patch)是一种特殊的图像格式,用于创建可拉伸的图形资源,这对于UI设计尤其重要。...通过理解9Patch的工作原理和使用方法,开发者可以更好地利用这些资源,提高应用的用户体验。

    android---draw9patch

    本文将深入探讨Draw9Patch的工作原理、使用方法以及在实际项目中的应用。 一、Draw9Patch简介 Draw9Patch,也称为9宫格图,是一种特殊的PNG图片格式,它通过在图片边缘添加额外的像素来定义可拉伸和不可拉伸的区域...

    shell中常用的命令之diff和patch用法

    然后,使用`patch`应用补丁: ```bash patch file2 file2.patch ``` 如果系统中未安装`patch`,可以通过包管理器安装,如在CentOS/RHEL中: ```bash yum install patch.x86_64 -y ``` ### 总结 `diff`和`patch`...

    详解Linux patch命令参数及用法

    总结,`patch`命令是Linux系统中不可或缺的工具,它简化了软件维护和更新的过程。熟练掌握其用法,能够帮助开发者和系统管理员更高效地管理和维护软件项目。在实际工作中,结合`diff`和`patch`,可以实现对源代码的...

    L4.1.15_2.0.1-patch_images_MX6ULLEVK.tar.gz

    《I.MX6ULL EVK 开发板镜像...理解其工作原理和使用方法,对于充分利用开发板的潜力,高效地进行嵌入式系统开发至关重要。通过熟练掌握这些知识点,开发者能够在短时间内构建起稳定的开发环境,推动项目快速向前进展。

Global site tag (gtag.js) - Google Analytics