Linux中國

diff 與 patch 的使用

摘要

在 Linux 的日常使用中,我們經常需要修改一些配置文件,然而在軟體升級以後,經常會面臨配置更新後與原配置部分不兼容的問題(當然我們更多的可能是來製作軟體升級的補丁)。在這種情況下我們通常有兩種選擇:

  • 對比現有配置,手動在新配置文件中改動
  • 利用 sedawk 等工具配合改動
  • 採用 diffpatch 製作增量補丁的方式改動

本文主要通過一個升級awesome 配置的例子,對第三種方法進行介紹和講解。

diff 介紹

diff 是一個文件比較工具,可以逐行比較兩個文件的不同,其中它有三種輸出方式,分別是 normalcontext 以及 unified。區別如下:

  • normal 方式為默認輸出方式,不需要加任何參數
  • context 相較於 normal 模式的簡單輸出,contetx 模式會輸出修改過部分的上下文,默認是前後 3 行。使用參數 -c
  • unified 合併上下文模式則為新的上下文輸出模式,同樣為前後 3 行,只不過把上下文合併了顯示了。使用參數 -u

:本文主要介紹 unified 模式

其他常用參數:

  • -r 遞歸處理目錄
  • -N 將缺失的文件當作空白文件處理

diff 語法與文件格式

diff [options] old new

先來看一個簡單的例子:

$ cat test1 
linux
linux
linux
linux
$ cat test2
locez
linux
locez
linux

此時輸入 diff -urN test1 test2 會輸出以下信息:

--- test1   2018-05-12 18:39:41.508375114 +0800
+++ test2   2018-05-12 18:41:00.124031736 +0800
@@ -1,4 +1,4 @@
+locez
 linux
-linux
-linux
+locez
 linux

先看前面 2 行,這兩行為文件的基本信息,--- 開頭為改變前的文件,+++ 開頭為更新後的文件。

--- test1   2018-05-12 18:39:41.508375114 +0800
+++ test2   2018-05-12 18:41:00.124031736 +0800

第三行為上下文描述塊,其中 -1,4 為舊文件的 4 行上下文,+1,4 為新文件的:

@@ -1,4 +1,4 @@

而具體到塊裡面的內容,前面有 - 號的則為刪除,有 + 號為新增,不帶符號則未做改變,僅僅是上下文輸出。

patch 介紹

patch 是一個可以將 diff 生成的補丁應用到源文件,生成一個打過補丁版本的文件。語法:

patch [oiption] [originalfile [patchfile]]

常用參數:

  • -i 指定補丁文件
  • -pNumdiff 生成的補丁中,第一二行是文件信息,其中文件名是可以包含路徑的,例如 --- /tmp/test1 2018-05-12 18:39:41.508375114 +0800 其中 -p0 代表完整的路徑 /tmp/test1,而 -p1 則指 tmp/test1-pN 依此類推
  • -E 刪除應用補丁後為空文件的文件
  • -o 輸出到一個文件而不是直接覆蓋文件

應用

awesome 桌面 3.5 與 4.0 之間的升級是不兼容的,所以在升級完 4.0 以後,awesome 桌面部分功能無法使用,因此需要遷移到新配置,接下來則應用 diffpatch 實現遷移,當然你也可以單純使用 diff 找出不同,然後手動修改新配置。

現在有以下幾個文件:

  • rc.lua.3.5 3.5 版本的默認配置文件,未修改
  • rc.lua.myconfig 基於 3.5 版本的個人配置文件
  • rc.lua.4.2 4.2 新默認配置,未修改

思路為利用 diff 提取出個人配置與 3.5 默認配置文件的增量補丁,然後把補丁應用在 4.2 的文件上實現遷移。

製作補丁

$ diff -urN rc.lua.3.5 rc.lua.myconfig  > mypatch.patch

應用補丁

$ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
patching file rc.lua (read from rc.lua.4.2)
Hunk #1 FAILED at 38.
Hunk #2 FAILED at 55.
Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
2 out of 4 hunks FAILED -- saving rejects to file rc.lua.rej

顯然應用沒有完全成功,其中在 38 行以及 55 行應用失敗,並記錄在 rc.lua.rej 里。

$ cat rc.lua.rej 
--- rc.lua.3.5  2018-05-12 19:15:54.922286085 +0800
+++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
@@ -38,10 +38,10 @@

 -- {{{ Variable definitions
 -- Themes define colours, icons, font and wallpapers.
-beautiful.init("@AWESOME_THEMES_PATH@/default/theme.lua")
+beautiful.init("~/.config/awesome/default/theme.lua")

 -- This is used later as the default terminal and editor to run.
-terminal = "xterm"
+terminal = "xfce4-terminal"
 editor = os.getenv("EDITOR") or "nano"
 editor_cmd = terminal .. " -e " .. editor

@@ -55,18 +55,18 @@
 -- Table of layouts to cover with awful.layout.inc, order matters.
 local layouts =
 {
-    awful.layout.suit.floating,
-    awful.layout.suit.tile,
-    awful.layout.suit.tile.left,
-    awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
+--    awful.layout.suit.floating,
+--    awful.layout.suit.tile,
+--    awful.layout.suit.tile.left,
+--    awful.layout.suit.tile.bottom,
+--    awful.layout.suit.tile.top,
     awful.layout.suit.fair,
     awful.layout.suit.fair.horizontal,
     awful.layout.suit.spiral,
     awful.layout.suit.spiral.dwindle,
     awful.layout.suit.max,
     awful.layout.suit.max.fullscreen,
-    awful.layout.suit.magnifier
+--    awful.layout.suit.magnifier
 }
 -- }}}

這裡是主題,終端,以及常用布局的個人設置。

修正補丁

再次通過對比補丁文件與 4.2 文件,發現 38 行區塊是要刪除的東西不匹配,而 55 行區塊則是上下文與要刪除的內容均不匹配,導致不能應用補丁,於是手動修改補丁

$ vim mypatch.patch
--- rc.lua.3.5  2018-05-12 19:15:54.922286085 +0800
+++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
@@ -38,10 +38,10 @@

 -- {{{ Variable definitions
 -- Themes define colours, icons, font and wallpapers.
-beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
+beautiful.init("~/.config/awesome/default/theme.lua")

 -- This is used later as the default terminal and editor to run.
-terminal = "xterm"
+terminal = "xfce4-terminal"
 editor = os.getenv("EDITOR") or "nano"
 editor_cmd = terminal .. " -e " .. editor

@@ -55,18 +55,18 @@

 -- Table of layouts to cover with awful.layout.inc, order matters.
 awful.layout.layouts = {
-    awful.layout.suit.floating,
-    awful.layout.suit.tile,
-    awful.layout.suit.tile.left,
-    awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
+--    awful.layout.suit.floating,
+--    awful.layout.suit.tile,
+--    awful.layout.suit.tile.left,
+--    awful.layout.suit.tile.bottom,
+--    awful.layout.suit.tile.top,
     awful.layout.suit.fair,
     awful.layout.suit.fair.horizontal,
     awful.layout.suit.spiral,
     awful.layout.suit.spiral.dwindle,
     awful.layout.suit.max,
     awful.layout.suit.max.fullscreen,
-    awful.layout.suit.magnifier,
+--    awful.layout.suit.magnifier,
     awful.layout.suit.corner.nw,
     -- awful.layout.suit.corner.ne,
     -- awful.layout.suit.corner.sw,
....
....

輸出省略顯示,有興趣的讀者可以仔細與rc.lua.rej 文件對比,看看筆者是怎樣改的。

再次應用補丁

$ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
patching file rc.lua (read from rc.lua.4.2)
Hunk #1 succeeded at 41 (offset 3 lines).
Hunk #2 succeeded at 57 with fuzz 2 (offset 2 lines).
Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
$ cp rc.lua ~/.config/awesome/rc.lua  ### 打完補丁直接使用

總結

diffpatch 配合使用,能當增量備份,而且還可以將補丁分發給他人使用,而且在日常的軟體包打補丁也具有重要的意義,特別是內核補丁或者一些驅動補丁,打補丁遇到錯誤時候可以嘗試自己修改,已滿足自身特殊要求,修改的時候一定要抓住 2 個非常重要的要素:

  1. 要修改的內容是否匹配?特別是要刪除的
  2. 上下文是否滿足,特別是距離要修改的地方前後一行,以及上下文的行數是否滿足,默認是 3 行上下文

本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國