- 為什麼 patch?
- 檔案( 版本 )之間的差異,可以指令 diff 儲存在一個 patch 檔案。
- 若舊版本需要修改,只要將 patch 檔案釋出。
- 使用者可以指令 patch,配合 patch 檔案中記錄之新舊版差異,將舊版程式更新。
- 使用者若發現並修正一個程式的臭蟲,簡單、正確的方式是,寄一個 patch 檔案給作者,而不要只是說明修正的地方。
- diff 指令:比對兩個檔案之間的差異,一般是用在 ASCII 純文字檔的比對上。
- diff 指令用法:
[root@linux ~]# diff [-bBiqn] from-file to-file 選項: from-file :檔名,作為原始比對檔案的檔名; to-file :檔名,作為目的比對檔案的檔名; # from-file 或 to-file 可以 - 取代, - 代表『Standard input』。 -b :忽略一行當中,多個空白的差異 (例如 "about me" 與 "about me" 視為相同) -B :忽略空白行的差異。 -i :忽略大小寫的不同。 -q :只列出檔案是否有差異。 -n :以 RCS 格式輸出檔案之差異。 -c (-C NUM) :兩個檔案皆加入差異部分前後 NUM 行,以增加輸出之可讀性。預設 NUM=3。 -u (-U NUM) :加入差異部分前後 NUM 行,以增加輸出之可讀性。預設 NUM=3。
- 預處理:將 /etc/passwd 第四行刪除,第六行取代為『no six line』,新的檔案放到 /tmp/test。
[root@linux ~]# mkdir -p /tmp/test [root@linux ~]# cat /etc/passwd | \ > sed -e '4d' -e '6c no six line' > /tmp/test/passwd # sed 後面若要接超過兩個以上的動作時,每個動作前面得加 -e 。
- 比對 /tmp/test/passwd 與 /etc/passwd 的差異。
[root@dywHome2 ~]# diff /etc/passwd /tmp/test/passwd 4d3 < adm:x:3:4:adm:/var/adm:/bin/sh 6c5 < sync:x:5:0:sync:/sbin:/bin/sync --- > no six line
- 只列出檔案是否有差異。
[root@dywHome2 ~]# diff -q /etc/passwd /tmp/test/passwd
- 以 RCS 格式輸出檔案之差異。
[root@dywHome2 ~]# diff -n /etc/passwd /tmp/test/passwd d4 1 d6 1 a6 1 no six line
- 加入差異部分前後 3 行,以增加輸出之可讀性。
[root@dywHome2 tmp]# diff -u old/ new/ > test.patch [root@dywHome2 tmp]# cat test.patch diff -u old/passwd new/passwd --- old/passwd 2008-04-16 13:14:50.000000000 -0400 +++ new/passwd 2008-04-16 11:15:12.000000000 -0400 @@ -1,9 +1,8 @@ root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/bin/sh daemon:x:2:2:daemon:/sbin:/bin/sh -adm:x:3:4:adm:/var/adm:/bin/sh lp:x:4:7:lp:/var/spool/lpd:/bin/sh -sync:x:5:0:sync:/sbin:/bin/sync +no six line shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/bin/sh
- 比對 /etc 與 /tmp/test 的差異。
[root@linux ~]# diff /etc /tmp/test ......(前面省略)..... Only in /etc: paper.config diff /etc/passwd /tmp/test/passwd 4d3 < adm:x:3:4:adm:/var/adm:/sbin/nologin 6c5 < sync:x:5:0:sync:/sbin:/bin/sync --- > no six line Only in /etc: passwd- ......(後面省略).....
- diff 指令用法:
- cmp:主要利用『位元』單位去比對(diff 主要是以『行』為單位比對,cmp 則是以『位元』為單位去比對)。
- cmp 指令用法:
[root@linux ~]# cmp [-bcsi] file1 file2 選項: -b :列出第一個的不同點之字元。 -c :同上。 -i SKIP1:SKIP2 : file1 與 file2 分別忽略前 SKIP1 與 SKIP2 位元。 -s :安靜模式,不顯示任何訊息。
- 用 cmp 比較 /etc/passwd 與 /tmp/test/passwd
[root@dywHome2 ~]# cmp /etc/passwd /tmp/test/passwd /etc/passwd /tmp/test/passwd differ: byte 94, line 4 # 不同點在第四行,而且位元數是在第 94 個位元。
- 列出第一個的不同點之字元
[root@dywHome2 ~]# cmp -c /etc/passwd /tmp/test/passwd /etc/passwd /tmp/test/passwd differ: byte 94, line 4 is 141 a 154 l # 不同點在檔案 /etc/passwd 的第一個字元為 a,在檔案 /tmp/test/passwd 的第一個字元為 l。 # 字元 a 之八進位碼為 141,字元 l 之八進位碼為 154。
- 以 printf 驗證 ASCII 之字元
[root@dywHome2 ~]# printf '\x61\t\x6c\n' a l # \xNN : NN 為十六進位
- cmp 指令用法:
- patch:檔案補丁。需與 diff 配合使用。
- patch 指令用法
[root@linux ~]# patch [OPTION]... [ORIGFILE [PATCHFILE]] 選項: -pNUM :取消 NUM 層目錄。 例如:假設檔名 /u/howard/src/blurfl/blurfl.c -p0 :代表 u/howard/src/blurfl/blurfl.c -p4 :代表 blurfl/blurfl.c -l :忽略空白之差異。 -i PATCHFILE :從 PATCHFILE 讀取補丁。 -o FILE :輸出補丁到檔案 FILE。 -r FILE :輸出錯誤到檔案 FILE。
- 預處理:建立兩個不同版本的檔案 /tmp/test/passwd 與 /etc/passwd。
[root@dywHome2 ~]# mkdir /tmp/old; cp /etc/passwd /tmp/old [root@dywHome2 ~]# mkdir /tmp/new; cp /tmp/test/passwd /tmp/new
- 建立補丁檔案 /tmp/test.patch 記錄新舊檔案之間的差異。
[root@dywHome2 ~]# cd /tmp ; diff old/ new/ > test.patch # diff 製作檔案時,舊的檔案必須是在前面,亦即是 diff oldfile newfile。
- 將舊的內容 (/tmp/old/passwd) 更新到新版 (/tmp/new/passwd) 的內容
[root@dywHome2 tmp]# cd /tmp/old [root@dywHome2 old]# patch passwd -i /tmp/test.patch patching file passwd # 選項 -i 亦可省略
- 更新內容,並指定存於 passwd1
[root@dywHome2 old]# patch passwd /tmp/test.patch -o passwd1 patching file passwd
- 內容已更新,若再做一次補丁,系統會詢問是否執行?
- 預設回答 n(o):系統會將錯誤訊息存在 passwd.rej
[root@dywHome2 old]# patch passwd -i /tmp/test.patch patching file passwd Reversed (or previously applied) patch detected! Assume -R? [n] n Apply anyway? [n] n Skipping patch. 2 out of 2 hunks ignored -- saving rejects to file passwd.rej
- 回答 y(es):系統會將更新後的內容存在 passwd.orig
[root@dywHome2 old]# patch passwd -i /tmp/test.patch patching file passwd Reversed (or previously applied) patch detected! Assume -R? [n] y
- 查詢檔案
[root@dywHome2 old]# ll passwd* -rw-r--r-- 1 root root 1207 Apr 16 13:14 passwd -rw------- 1 root root 1156 Apr 16 13:10 passwd1 -rw-r--r-- 1 root root 1156 Apr 16 13:11 passwd.orig -rw-r--r-- 1 root root 149 Apr 16 13:12 passwd.rej
- 預設回答 n(o):系統會將錯誤訊息存在 passwd.rej
- 使用選項 -pNUM 更新舊版資料
- 變換目錄至 /tmp
[root@dywHome2 old]# cd ..
- 以選項 -u 建立 目錄 old/ 與 new/ 下檔案之差異檔,再回到目錄 /tmp/old。
[root@dywHome2 tmp]# diff -u old/ new/ > /tmp/test.patch [root@dywHome2 tmp]# cd old
- test.patch 儲存 diff -u old/passwd new/passwd,故必須一層目錄,即 -p1。
[root@dywHome2 old]# patch -p1 </tmp/test.patch patching file passwd
- 若使用 -p0,則無法找到要更新的檔案,系統會要求輸入要更新的檔案。
[root@dywHome2 old]# patch -p0 </tmp/test.patch can't find file to patch at input line 4 Perhaps you used the wrong -p or --strip option? The text leading up to this was: -------------------------- |diff -u old/passwd new/passwd |--- old/passwd 2008-04-16 14:46:21.000000000 -0400 |+++ new/passwd 2008-04-16 11:15:12.000000000 -0400 -------------------------- File to patch:
- 命令
patch -pnum <patchfile>
適用於目錄下多個檔案,較接近實際狀況。
- 變換目錄至 /tmp
- patch 指令用法
- 範例:利用 patch 命令及第一版檔案、第一版和第二版的差異檔案,產生完整的第二版檔案。
- 第一版的檔案 file1.c:
This is file one line 2 line 3 there is no line 4, this is line 5 line 6
- 產生第二版的檔案 file2.c:
This is file two line 2 line 3 line 4 line 5 line 6 a new line 8
- 利用 diff 命令產生差異:
$ diff file1.c file2.c > diffs diffs 檔案如下: 1c1 < This is file one — > This is file two 4c4,5 < there is no line 4, this is line 5 — > line 4 > line 5 5a7 > a new line 8
- 假設有 file1.c 和 diffs 檔案。可以利用 patch 命令更新 file1.c,使其與 file2.c 一樣。
$ patch file1.c diffs Hmm... Looks like a normal diff to me... Patching file file1.c using Plan A... Hunk #1 succeeded at 1. Hunk #2 succeeded at 4. Hunk #3 succeeded at 7. done $
- 若希望回覆 file1.c ,只要再使用 patch,加上-R(反向 patch)選項,file1.c 就會回到原本的狀況。。
$ patch -R file1.c diffs Hmm... Looks like a normal diff to me... Patching file file1.c using Plan A... Hunk #1 succeeded at 1. Hunk #2 succeeded at 4. Hunk #3 succeeded at 6. done $
- 第一版的檔案 file1.c:
- 例題:完成下列工作。
- 以 vi 在 printf.txt 最後加入一行 csie - - -,並另存為 printf.new;
- 以 diff 比較 printf.txt 及 printf.new,並建立其 patch file,printf.patch;
- 以 cmp 比較 printf.txt 及 printf.new;
- 利用 patch file,printf.patch 將 printf.txt 更新為 printf.new。