diff命令
diff命令时unix中用来比较文件差异的工具,也通常用于代码管理中。
diff命令显示结果有三种格式:
- 正常格式(normal diff)
diff f1 f2
- 上下文格式(context diff)
diff -c f1 f2
- 合并格式(unified diff)
diff -u f1 f2
- side-by-side格式
diff -y f1 f2
比较文件的内容:
1 | [root@localhost b]# cat -n f1 |
正常格式
1 | [root@localhost b]# diff f1 f2 |
上下文格式
上个世纪80年代初,加州大学伯克利分校推出BSD版本的Unix时,觉得diff的显示结果太简单,最好加入上下文,便于了解发生的变动。因此,推出了上下文格式的diff
可以通过diff -C Num
或diff --context[=Num]
的方式指定显示上下文的行数,默认为3行(前三行加后三行)
1 | [root@localhost b]# diff f1 f2 -c |
合并格式
如果两个文件相似度很高,那么上下文格式的diff,将显示大量重复的内容,很浪费空间。1990年,GNU diff率先推出了”合并格式”的diff,将f1和f2的上下文合并在一起显示
可以通过diff -U Num
或diff --unified[=Num]
的方式指定显示上下文的行数,默认为3行(前三行加后三行)
1 | [root@localhost b]# diff f1 f2 -u |
side-by-side格式
这种格式下,会将两个文件的内容分成两列对比展示出来
1 | [root@localhost b]# diff -y -W 20 f1 f2 |
命令格式说明
diff [选项] [文件1或目录1] [文件2或目录2](四种组合方式)
比较两个文件时,如果其中一个文件为
-
符号,表示从标准输入读取,以ctrl+d
结束输入
如果输入的参数一个时文件,一个是目录时,会在该目录下查找同名文件进行比较,如果文件不存,则提示失败
如果输入的参数是两个目录时,也是只比较目录下的同名文件,默认是只比较目录下的文件,不会递归比较子目录
diff命令返回0 表示无差异,返回1 表示有差异, 返回2 表示命令出错(如文件不存在等)
常用的选项
选项 | 说明 |
---|---|
--normal |
正常格式进行展示,如果不指定显示格式,默认为正常格式 |
-c 或-C NUM 或--context=NUM |
按照上下文格式进行展示 |
-u 或-U NUM 或--unified=NUM |
按照合并格式进行展示 |
-y 或--side-by-side |
按照side-by-side格式进行展示 |
-W NUM 或--width=NUm |
指定-y 模式下显示的总列数,默认为130 |
--suppress-common-lines |
指定-y 模式下,不显示相同内容的行 |
-r 或--recursive |
递归比较子目录 |
-x 或--exclude=PAT |
排除与PAT(pattern样式)匹配的文件 |
-X 或--exculde-from=FILE |
排除与FILE中样式匹配的文件 |
-i 或--ignore-case |
忽略大小写的区别 |
-b 或--ignore-space-change |
忽略空格的差异 |
-w 或--ignore-all-space |
忽略所有的空白差异 |
-B 或--ignore-blank-line |
忽略空白行差异 |
-I RE 或--ignore-matching-lines=RE |
忽略所有匹配RE(regexp正则表达式)的行的更改 |
-Z 或--ignore-trailing-space |
忽略行尾空格 |
-E 或--ignore-tab-expansion |
忽略tab扩展差异 |
--ignore-file-name-case |
比较时忽略文件大小写 |
--no-ignore-file-name-case |
比较时不忽略文件大小写 |
--ignore-file-name-case |
比较时忽略文件大小写 |
-N 或--new-file |
比较目录时,如果f3只在a目录中存在,默认会输出Only in a: f3 ,如果配置了该参数后,diff命令会将f3文件与一个空白文件进行对比 |
-p 或--show-c-function |
如果比较的文件时c语言源文件,显示差异所在的函数名 |
-P 或--unidirectional-new-file |
与 -N 类似,只有当第二个目录包含了第一个目录没有的文件时,才会将这个文件与空白文件做对比 |
patch命令
执行patch命令时,patch文件中定义的修改后的目录不能存在
patch命令说明
patch命令的使用有两种格式
- 如果针对单文件打补丁:
patch [option] [originalfile [patchfile]]
- 同时常用更多的方式为:
patch -pnum < patchfile
常用的命令选项
| 名称 | 说明 |
| ———————- | ———————————————————————————————————————————————— |
| --dry-run
| 只是打印应用补丁后的结果,并不会实际修改文件 |
| -R
或 --reverse
| 该命令执行时会假设补丁文件是通过交换ori和mod参数,实际上可以对打过补丁后的文件做回滚操作 |
| -b
或--backup
| 对每一个修改的文件做备份,会生成xxx.orig备份文件 |
| -pNum
或--strip=NUM
| 设置执行命令时会去除patchfile中的几层路径名。0表示不删除,使用patchfile中的全路径,如果未指定该参数或NUM设置有问题,会提示找不到需要打补丁的文件 |
diff + patch的补丁应用
如果是对目录制作补丁文件,目录应该使用相对路径,不要使用绝对路径
两个目录的结构要一样
根据修改后目录的内容不同,生成补丁的方式也会不一样
如果mod的目录中只包含了对ori目录中某些文件的修改或新增了某些文件
diff -urP src_ori_dir src_mod_dir > src.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40[root@localhost test_diff_patch]# tree ./src_ori
./src_ori # ori目录中有两个文件 123 和 abc,文件中的内容与文件名相同
├── 123
└── abc
0 directories, 2 files
[root@localhost test_diff_patch]# cat ./src_ori/*
123
abc
##
patch中修改了abc文件的内容为bbb,并新增了文件ccc
##
[root@localhost test_diff_patch]# cat src.patch
Only in src_ori: 123
diff -ruP src_ori/abc src_mod/abc
--- src_ori/abc 2020-05-23 14:25:13.895198462 +0800
+++ src_mod/abc 2020-05-23 14:04:06.095735637 +0800
@@ -1 +1 @@
-abc
+bbb
diff -ruP src_ori/ccc src_mod/ccc
--- src_ori/ccc 1970-01-01 08:00:00.000000000 +0800
+++ src_mod/ccc 2020-05-23 14:25:41.160887860 +0800
@@ -0,0 +1 @@
+ccc
[root@localhost test_diff_patch]# patch -p0 < src.patch
patching file src_ori/abc
patching file src_ori/ccc
[root@localhost test_diff_patch]# tree ./src_ori
./src_ori # 执行了patch命令后,ori中多了ccc文件,abc的内容也变成了bbb
├── 123
├── abc
└── ccc
0 directories, 3 files
[root@localhost test_diff_patch]# cat ./src_ori/*
123
bbb
ccc
[root@localhost test_diff_patch]#只要mod的目录中有对ori目录文件做删除,那么mod目录中必须包含未删除ori中的其他所有文件
diff -urN src_ori_dir src_mod_dir > src.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46ori中文件内容与文件名相同
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ ll ./*/*
-rwxrwxrwx 1 baoze baoze 7 Jun 2 18:55 ./mod/aaa*
-rwxrwxrwx 1 baoze baoze 4 Jun 2 18:54 ./ori/aaa*
-rwxrwxrwx 1 baoze baoze 4 Jun 2 18:54 ./ori/bbb*
./ori/inner:
total 0
drwxrwxrwx 1 baoze baoze 512 Jun 2 18:54 ./
drwxrwxrwx 1 baoze baoze 512 Jun 2 18:54 ../
-rwxrwxrwx 1 baoze baoze 4 Jun 2 18:54 ccc*
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$
# mod中内容修改了aaa文件,删除了bbb和ccc文件
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ diff -ruN ori mod > mod.patch
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ cat mod.patch
diff -ruN ori/aaa mod/aaa
--- ori/aaa 2020-06-02 18:54:37.447786500 +0800
+++ mod/aaa 2020-06-02 18:55:36.400920500 +0800
@@ -1 +1 @@
-aaa
+newaaa
diff -ruN ori/bbb mod/bbb
--- ori/bbb 2020-06-02 18:54:42.786351600 +0800
+++ mod/bbb 1970-01-01 08:00:00.000000000 +0800
@@ -1 +0,0 @@
-bbb
diff -ruN ori/inner/ccc mod/inner/ccc
--- ori/inner/ccc 2020-06-02 18:54:29.759650700 +0800
+++ mod/inner/ccc 1970-01-01 08:00:00.000000000 +0800
@@ -1 +0,0 @@
-ccc
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$
对ori进行打补丁
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ patch -p0 < mod.patch
patching file ori/aaa
patching file ori/bbb
patching file ori/inner/ccc
打补丁后ori目录下只有aaa文件,内容也有修改
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ ll ori/
total 0
drwxrwxrwx 1 baoze baoze 512 Jun 2 19:08 ./
drwxrwxrwx 1 baoze baoze 512 Jun 2 19:06 ../
-rwxrwxrwx 1 baoze baoze 7 Jun 2 19:08 aaa*
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$ cat ori/aaa
newaaa
baoze@DESKTOP-EV6CLJE:/mnt/d/workspace/patch_test$