patch 程式
發表於 : 2012-06-11, 11:52
patch 程式
為什麼 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
3:4:adm:/var/adm:/bin/sh
6c5
< sync
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
0:0:root:/root:/bin/bash
bin
1:1:bin:/bin:/bin/sh
daemon
2:2:daemon:/sbin:/bin/sh
-adm
3:4:adm:/var/adm:/bin/sh
lp
4:7:lp:/var/spool/lpd:/bin/sh
-sync
5:0:sync:/sbin:/bin/sync
+no six line
shutdown
6:0:shutdown:/sbin:/sbin/shutdown
halt
7:0:halt:/sbin:/sbin/halt
mail
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
3:4:adm:/var/adm:/sbin/nologin
6c5
< sync
5:0:sync:/sbin:/bin/sync
---
> no six line
Only in /etc: passwd-
......(後面省略).....
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 為十六進位
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
使用選項 -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> 適用於目錄下多個檔案,較接近實際狀況。
範例:利用 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
$
例題:完成下列工作。
以 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。
為什麼 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
6c5
< 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
bin
daemon
-adm
lp
-sync
+no six line
shutdown
halt
比對 /etc 與 /tmp/test 的差異。
[root@linux ~]# diff /etc /tmp/test
......(前面省略).....
Only in /etc: paper.config
diff /etc/passwd /tmp/test/passwd
4d3
< adm
6c5
< sync
---
> no six line
Only in /etc: passwd-
......(後面省略).....
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 為十六進位
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
使用選項 -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> 適用於目錄下多個檔案,較接近實際狀況。
範例:利用 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
$
例題:完成下列工作。
以 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。