Linux diff 与 patch 命令完全指南:文件比较与补丁管理

Linux diff 与 patch 命令完全指南:文件比较与补丁管理

Someone Lv5

在 Linux 系统管理和软件开发中,文件比较补丁管理是两项基础而强大的技能。diff 命令用于逐行比较文件差异,patch 命令则根据差异文件(补丁)将变更应用到目标文件。这对组合是 Git 等版本控制系统的底层基石,也是运维人员日常排查配置变更、管理代码更新的得力工具。

本文将全面介绍 diff 和 patch 的核心用法、输出格式解读、实战场景以及高级技巧。

一、diff 命令详解

1.1 基本语法

1
diff [选项] 文件1 文件2

diff 比较两个文件,输出它们之间的差异行。如果两个文件完全相同,则无输出(或返回空)。

1.2 三种输出格式

diff 支持三种差异输出格式,其中**统一格式(unified)**是最常用和最易读的。

1.2.1 正常格式(normal)

默认输出,直接显示需要修改的行和操作:

1
diff /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf

输出示例:

1
2
3
4
5
6
2c2
< sendfile off;
---
> sendfile on;
5a6
> gzip on;
  • 2c2:文件1的第2行被替换为文件2的第2行
  • 5a6:在文件1的第5行之后追加文件2的第6行
  • < 开头:文件1的内容
  • > 开头:文件2的内容
  • ---:两部分的分隔线

操作符说明:

操作符含义示例
a追加(append)5a6 — 第5行后追加
c替换(change)2c2 — 第2行替换
d删除(delete)3d2 — 删除第3行

1.2.2 上下文格式(context,-c)

显示差异行周围的上下文(默认3行),适合查看变更的上下文:

1
diff -c nginx.conf.bak nginx.conf

输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*** nginx.conf.bak	2026-06-17 01:00:00.000000000 +0800
--- nginx.conf 2026-06-17 02:00:00.000000000 +0800
***************
*** 1,6 ****
user www-data;
worker_processes auto;
! sendfile off;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
--- 1,7 ----
user www-data;
worker_processes auto;
! sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
+ gzip on;
  • *** 1,6 ****:文件1的第1-6行
  • --- 1,7 ----:文件2的第1-7行
  • ! 开头:有变更的行
  • + 开头:新增的行
  • - 开头:删除的行

1.2.3 统一格式(unified,-u)⭐推荐

合并上下文和变更标记,更紧凑易读。这是 Git diff 使用的格式,也是日常最推荐的方式:

1
diff -u nginx.conf.bak nginx.conf

输出示例:

1
2
3
4
5
6
7
8
9
10
--- nginx.conf.bak	2026-06-17 01:00:00.000000000 +0800
+++ nginx.conf 2026-06-17 02:00:00.000000000 +0800
@@ -1,6 +1,7 @@
user www-data;
worker_processes auto;
-sendfile off;
+sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
+gzip on;
  • @@ -1,6 +1,7 @@:文件1第1-6行 → 文件2第1-7行
  • - 删除的行
  • + 新增的行
  • 无前缀的行:共享的上下文

推荐使用 -u 选项——输出简洁、包含上下文、直接可用于 patch 命令。

1.3 常用选项速查

选项说明示例
-u统一格式输出(推荐)diff -u a.txt b.txt
-c上下文格式输出diff -c a.txt b.txt
-i忽略大小写差异diff -i a.txt b.txt
-w忽略空白字符差异diff -w a.txt b.txt
-b忽略空白数量变化diff -b a.txt b.txt
-r递归比较目录diff -r dir1 dir2
-q仅报告文件是否不同(安静模式)diff -q a.txt b.txt
-N将缺失文件视为空文件(配合 -r 使用)diff -ruN dir1 dir2
-x PAT排除匹配模式的文件diff -r -x node_modules d1 d2
--color彩色输出差异diff -u --color a.txt b.txt

1.4 递归比较目录

这是 diff 最强大的运维场景之一——比较两个目录树的差异:

1
2
3
4
5
6
7
8
9
10
11
# 递归比较两个配置目录
diff -rq /etc/nginx/sites-enabled/ /etc/nginx/sites-available/

# 递归比较并输出统一格式差异
diff -ruN /etc/nginx/ /backup/nginx/

# 只列出有差异的文件
diff -rq /var/www/html/ /var/www/html_bak/

# 排除特定目录
diff -ruN --exclude=cache --exclude=logs app/ app_new/

1.5 重定向差异输出到文件

1
2
3
4
5
# 生成补丁文件(供 patch 命令使用)
diff -u nginx.conf.bak nginx.conf > nginx.patch

# 递归生成目录级别补丁
diff -ruN config/ config_new/ > config-upgrade.patch

二、patch 命令详解

patch 命令将 diff 生成的补丁文件应用到目标文件或目录,实现自动化变更。

2.1 基本语法

1
2
patch [选项] < 补丁文件
patch 目标文件 < 补丁文件

2.2 应用补丁的两种方式

方式一:预先指定目标

1
2
diff -u origin.conf modified.conf > change.patch
patch origin.conf < change.patch # 将 change.patch 应用到 origin.conf

执行后 origin.conf 被修改为与 modified.conf 一致。

方式二:补丁内包含路径信息(推荐)

1
2
3
4
5
# 生成补丁时保留路径
diff -u /etc/nginx/nginx.conf.orig /etc/nginx/nginx.conf > nginx.patch

# 在任意位置应用
patch -p0 < nginx.patch

-pN 参数指定剥离路径前缀的层数:

参数路径处理示例文件路径
-p0使用完整路径/etc/nginx/nginx.conf
-p1剥离第一级etc/nginx/nginx.conf
-p3剥离三级nginx.conf

2.3 patch 常用选项

选项说明示例
-pN剥离路径前缀 N 级patch -p1 < patch.diff
-R反向应用补丁(回滚)patch -R < patch.diff
--dry-run试运行(不实际修改,检查兼容性)patch --dry-run < patch.diff
-b备份原文件(生成 .orig 文件)patch -b < patch.diff
-B PREFIX备份文件前缀patch -B .bak~ < patch.diff
-d DIR在指定目录下执行 patchingpatch -d /etc/nginx < patch.diff
-i FILE从文件读取补丁patch -i change.patch
-E应用补丁后删除空文件patch -E < patch.diff
-s静默模式(仅输出错误)patch -s < patch.diff

2.4 安全先行:dry-run 试运行

在实际应用补丁之前,务必先试运行:

1
2
patch --dry-run < change.patch
# 输出:checking file nginx.conf

如果输出类似 Hunk #1 FAILED at 1.,说明补丁与当前文件不匹配,需要手动检查。

三、实战场景

场景 1:配置文件变更管理

运维人员修改 Nginx 配置前先备份,然后生成补丁方便回滚:

1
2
3
4
5
6
7
8
# 备份
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d)

# 修改后生成补丁
diff -u /etc/nginx/nginx.conf.$(date +%Y%m%d) /etc/nginx/nginx.conf > ~/nginx-change.patch

# 需要回滚时
patch -R /etc/nginx/nginx.conf < ~/nginx-change.patch

场景 2:源码级热修复

当远端服务器不能直接使用 Git,但需要应用代码修改时:

1
2
3
4
5
6
7
# 本地开发环境生成补丁
cd /home/dev/project
diff -u src/app.js.orig src/app.js > fix-login.patch

# 复制到生产服务器并应用
scp fix-login.patch user@prod-server:/tmp/
ssh user@prod-server "cd /var/www/app && patch -p1 < /tmp/fix-login.patch"

场景 3:目录级别批量管理

1
2
3
4
5
6
7
8
9
10
# 生成完整项目补丁
diff -ruN project-v1/ project-v2/ --exclude=.git --exclude=node_modules > upgrade-v2.patch

# 查看补丁大小和概要
wc -l upgrade-v2.patch
head -50 upgrade-v2.patch

# 在另一台机器上应用
cd /opt/project
patch -p1 < /tmp/upgrade-v2.patch

场景 4:反向补丁回滚

1
2
3
4
5
# 已经应用了补丁,需要回退
patch -R -p1 < change.patch

# 或使用 -R 试运行确认
patch -R --dry-run -p1 < change.patch

场景 5:仅查看差异的文件列表

1
2
3
4
5
6
7
8
# 查看两个目录中有哪些文件不同
diff -rq config/ config-bak/ | grep -v "Only in"

# 仅输出差异文件的数量
diff -rq config/ config-bak/ | wc -l

# 输出仅在源目录中存在的文件
diff -rq config/ config-bak/ | grep "Only in config/"

四、常见问题排查

问题现象解决方案
补丁失败:Hunk 不匹配Hunk #1 FAILED at 10.目标文件已被修改,与生成补丁时的版本不一致。重新生成补丁或手动合并。
路径不匹配can't find file to patch调整 -pN 参数级别。先用 patch --dry-run 测试不同 -p 值。
空白字符差异diff 输出大量无实质变化的差异使用 -w-b 忽略空白差异生成补丁。
二进制文件比较diff 输出 Binary files differ使用 diff -a 强制文本模式,或用 md5sum 校验。
大目录比较过慢diff -r 对大量文件执行缓慢先用 diff -rq 列出差异文件,再对特定文件生成补丁。
换行符不一致Windows (CRLF) vs Linux (LF)使用 diff -w 忽略空白差异,或先用 dos2unix 统一换行符。
补丁部分应用某些 Hunk 成功,某些失败使用 --force 强制应用失败的 Hunk(谨慎!),或手动编辑补丁文件修正偏移量。

五、diff 和 patch 的进阶技巧

5.1 与 Git 的关系

Git 内部使用的差异算法就是 diff 的一种扩展,git diff 的输出就是 unified diff 格式:

1
2
3
4
5
6
7
8
9
10
# Git diff 输出示例
git diff src/app.js

# 导出 Git 差异为补丁文件
git diff > my-changes.patch
git format-patch HEAD~1 # 生成更完整的补丁(含 commit 信息)

# 应用 Git 补丁
patch -p1 < my-changes.patch
git am < 0001-fix-bug.patch # 使用 git am 应用 format-patch 生成的补丁

5.2 彩色差异化输出

1
2
3
4
5
# diff 自带彩色支持(GNU diffutils 3.4+)
diff -u --color=always origin.conf modified.conf

# 使用 colordiff 工具
colordiff -u origin.conf modified.conf

5.3 比较非文本文件

1
2
3
4
5
6
7
# 比较 PDF/DOCX 等二进制文件时,diff 只报告是否相同
diff -q doc1.pdf doc2.pdf
# 输出:Binary files doc1.pdf and doc2.pdf differ

# 使用专用工具
# apt install diffpdf
diffpdf doc1.pdf doc2.pdf

5.4 使用 diff3 三路合并

diff3 是 diff 的扩展,比较三个文件,常用于合并多个修改版本:

1
diff3 -m my-file.txt base.txt their-file.txt > merged.txt

5.5 交互式补丁应用(sdiff)

sdiff 并排显示两个文件的差异:

1
sdiff -w 120 nginx.conf.bak nginx.conf

六、最佳实践总结

  1. 始终用 -u 生成补丁 — unified 格式易读、可直接用于 patch
  2. 应用补丁前用 --dry-run — 先验证兼容性,避免破坏性操作
  3. 备份原始文件 — 使用 patch -b 自动生成 .orig 备份
  4. 使用 -p1 剥离一级路径 — 这是绝大多数开源项目的标准做法
  5. diff -rq 快速检查目录差异 — 确认哪些文件有变更再深入分析
  6. 反转补丁用 -R — 快速回滚不需要重新生成反向补丁
  7. 排除无关目录 — 使用 --exclude 跳过 .gitnode_modulescache

参考命令速查

场景命令
比较两个文件(统一格式)diff -u file1 file2
递归比较两个目录diff -ruN dir1 dir2
仅列出差异文件名diff -rq dir1 dir2
忽略空白差异diff -uw file1 file2
生成补丁文件diff -u old new > patch.diff
应用补丁patch -p1 < patch.diff
试运行补丁patch --dry-run -p1 < patch.diff
回滚补丁patch -R -p1 < patch.diff
带备份应用补丁patch -b -p1 < patch.diff
从文件读取补丁patch -i patch.diff
彩色 diff 输出diff -u --color=always a b
三路合并diff3 -m mine base theirs
并排比较sdiff -w 120 file1 file2

本文由AI辅助生成,内容仅供参考

  • 标题: Linux diff 与 patch 命令完全指南:文件比较与补丁管理
  • 作者: Someone
  • 创建于 : 2026-06-17 02:48:00
  • 更新于 : 2026-06-18 08:39:57
  • 链接: https://demo-blog.qusite.cn/2026-06-17-diff-patch-guide/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。