Lệnh diff: so sánh tệp, định dạng bản vá của diff -u và các tùy chọn
Lệnh diff là lệnh Linux so sánh hai tệp theo từng dòng và chỉ in ra những dòng khác nhau. Khi so sánh bằng diff một tệp cũ và một tệp mới mô phỏng cấu hình máy chủ web, ba chỗ thay đổi hiện ra thành ba dòng 2,3c2,3, 5d4 và 6a6, còn trong tệp vá lưu bằng tùy chọn -u, cùng những thay đổi đó được sắp xếp bằng dấu trừ và dấu cộng.
Tên tệp và nội dung trong kết quả bên dưới cùng thư mục làm việc /root/work là giá trị ví dụ. Tất cả các tệp được so sánh đều là tệp nhỏ tạo ra để thử nghiệm.
1️⃣ Cách dùng cơ bản của lệnh diff và cách đọc kết quả
Dạng cơ bản của lệnh lần lượt là diff, tùy chọn, tệp thứ nhất và tệp thứ hai. Lệnh in ra, kèm số dòng, những dòng nào cần sửa, xóa hoặc thêm để tệp thứ nhất giống tệp thứ hai.
Hai tệp dùng để so sánh là các tệp sáu dòng mô phỏng cấu hình máy chủ web.
cd /root/workcat config-old.conf# app config
listen 80
server_name example.com
root /var/www/html
gzip off
log_level warncat config-new.conf# app config
listen 443
server_name example.com www.example.com
root /var/www/html
log_level warn
cache onHai tệp được so sánh mà không có tùy chọn.
diff config-old.conf config-new.conf2,3c2,3
< listen 80
< server_name example.com
---
> listen 443
> server_name example.com www.example.com
5d4
< gzip off
6a6
> cache onecho $?1Trong kết quả, dòng vị trí và dòng nội dung xuất hiện xen kẽ. Chữ cái ở giữa dòng vị trí là c cho sửa, d cho xóa và a cho thêm; bên trái chữ cái là số dòng của tệp thứ nhất, bên phải là số dòng của tệp thứ hai. Nếu có chỗ khác nhau, mã thoát là 1.
| Đầu ra | Ý nghĩa |
|---|---|
| 2,3c2,3 | Sửa dòng 2–3 của tệp thứ nhất thành dòng 2–3 của tệp thứ hai (change) |
| 5d4 | Xóa dòng 5 của tệp thứ nhất (delete). Sau khi xóa, vị trí khớp với sau dòng 4 của tệp thứ hai |
| 6a6 | Thêm dòng 6 của tệp thứ hai vào sau dòng 6 của tệp thứ nhất (add) |
| < dòng | Dòng có trong tệp thứ nhất |
| > dòng | Dòng có trong tệp thứ hai |
| --- | Ranh giới giữa phía tệp thứ nhất và phía tệp thứ hai trong các dòng bị sửa (c) |
Khi so sánh các tệp có nội dung giống nhau, lệnh không in gì và kết thúc với mã thoát 0.
diff config-old.conf config-copy.confecho $?0Nếu đưa vào một tệp không tồn tại, thông báo lỗi xuất hiện và mã thoát là 2.
diff config-old.conf nosuch.confdiff: nosuch.conf: No such file or directoryecho $?2Trong script, ba giá trị này dùng để phân biệt giống nhau, khác nhau và lỗi.
2️⃣ Định dạng hợp nhất của diff -u và tệp vá
Kết quả mặc định chỉ có những dòng thay đổi, nên trong tệp cấu hình dài hàng trăm dòng, khó biết những dòng đó nằm gần thiết lập nào. Thêm -u thì kết quả ở định dạng hợp nhất (unified), gộp cả tối đa ba dòng trước và sau các dòng thay đổi.
diff -u config-old.conf config-new.conf--- config-old.conf 2026-10-29 02:24:50.840228932 +0000
+++ config-new.conf 2026-10-29 02:24:50.840228932 +0000
@@ -1,6 +1,6 @@
# app config
-listen 80
-server_name example.com
+listen 443
+server_name example.com www.example.com
root /var/www/html
-gzip off
log_level warn
+cache onHai dòng đầu (---, +++) cho biết tên và thời gian sửa đổi của hai tệp, còn dòng @@ -1,6 +1,6 @@ là một khối (hunk) gộp 6 dòng tính từ dòng 1 của tệp thứ nhất với 6 dòng tính từ dòng 1 của tệp thứ hai. Ở các dòng bên dưới, dấu - ở đầu là dòng bị xóa khỏi tệp thứ nhất, dấu + là dòng được thêm vào tệp thứ hai, còn khoảng trắng là dòng giống nhau ở cả hai tệp.
-c là định dạng ngữ cảnh (context). Khối của tệp thứ nhất và khối của tệp thứ hai được in riêng, với dấu chấm than trước dòng bị sửa, dấu trừ ở dòng bị xóa và dấu cộng ở dòng được thêm.
diff -c config-old.conf config-new.conf*** config-old.conf Thu Oct 29 02:24:50 2026
--- config-new.conf Thu Oct 29 02:24:50 2026
***************
*** 1,6 ****
# app config
! listen 80
! server_name example.com
root /var/www/html
- gzip off
log_level warn
--- 1,6 ----
# app config
! listen 443
! server_name example.com www.example.com
root /var/www/html
log_level warn
+ cache onCùng một thay đổi nhưng -c dài hơn -u vì các dòng không đổi xuất hiện một lần trong mỗi khối.
Lưu kết quả của -u vào tệp thì tệp đó chính là tệp vá. Dù kết quả được chuyển vào tệp, mã thoát của diff vẫn là 1.
diff -u config-old.conf config-new.conf > /root/work/config.patchecho $?1cat /root/work/config.patch--- config-old.conf 2026-10-29 02:24:50.840228932 +0000
+++ config-new.conf 2026-10-29 02:24:50.840228932 +0000
@@ -1,6 +1,6 @@
# app config
-listen 80
-server_name example.com
+listen 443
+server_name example.com www.example.com
root /var/www/html
-gzip off
log_level warn
+cache onNội dung của tệp đã lưu giống với kết quả -u đã in trên màn hình. Đưa tệp này cho lệnh patch thì có thể biến tệp thứ nhất thành cùng nội dung với tệp thứ hai.
3️⃣ Các tùy chọn của diff và bỏ qua khoảng trắng, chữ hoa chữ thường
Khi chép cấu hình bằng tay, sẽ có những dòng nội dung giống nhau nhưng chỉ khác chữ hoa chữ thường hoặc khoảng trắng. Cặp tệp ví dụ thứ hai đổi chữ L hoa ở dòng đầu thành chữ thường, đổi một khoảng trắng ở dòng thứ hai thành hai và thêm một dòng trống.
cat case-a.txtListen 80
ServerName example.com
DocumentRoot /var/www/htmlcat case-b.txtlisten 80
ServerName example.com
DocumentRoot /var/www/htmldiff case-a.txt case-b.txt1,2c1,3
< Listen 80
< ServerName example.com
---
> listen 80
> ServerName example.com
>Khi so sánh không có tùy chọn, dòng 1–2 vốn cùng nghĩa cũng hiện ra là dòng thay đổi. Bỏ qua chữ hoa chữ thường bằng -i thì dòng Listen biến mất và chỉ còn dòng 2 của tệp thứ nhất.
diff -i case-a.txt case-b.txt2c2,3
< ServerName example.com
---
> ServerName example.com
>Thêm -w thì mọi khoảng trắng trong dòng đều bị bỏ qua, nên dòng ServerName cũng thành dòng giống nhau và chỉ còn một dòng trống được thêm ở dòng 3. Dùng -b, chỉ bỏ qua số lượng khoảng trắng, thay cho -w cũng cho cùng kết quả với các tệp này.
diff -i -w case-a.txt case-b.txt2a3
>Thêm cả -B thì khác biệt về dòng trống cũng bị bỏ qua, nên lệnh kết thúc với mã thoát 0 mà không in gì.
diff -i -w -B case-a.txt case-b.txtecho $?0Để xem hai tệp cạnh nhau ở bên trái và bên phải, dùng -y. Chiều rộng mặc định là 130 cột nên đã được thu lại bằng -W 70.
diff -y -W 70 config-old.conf config-new.conf# app config # app config
listen 80 | listen 443
server_name example.com | server_name example.com www.ex
root /var/www/html root /var/www/html
gzip off <
log_level warn log_level warn
> cache onVạch dọc (|) ở giữa là dòng thay đổi, < là dòng chỉ có trong tệp thứ nhất và > là dòng chỉ có trong tệp thứ hai. Khi thu hẹp chiều rộng, các dòng dài bị cắt. Dòng server_name ở bên phải chỉ hiện đến www.ex.
Thêm --suppress-common-lines thì các dòng giống nhau bị bỏ đi và chỉ còn các dòng khác nhau.
diff -y --suppress-common-lines -W 70 config-old.conf config-new.conflisten 80 | listen 443
server_name example.com | server_name example.com www.ex
gzip off <
> cache onKhi chỉ cần kiểm tra các tệp giống hay khác nhau chứ không cần nội dung khác biệt, dùng -q. Khi các tệp giống nhau, -q không in gì, nên muốn nhận một dòng báo rằng chúng giống nhau thì dùng -s.
diff -q config-old.conf config-new.confFiles config-old.conf and config-new.conf differdiff -s config-old.conf config-copy.confFiles config-old.conf and config-copy.conf are identicalCác tùy chọn được gom vào hai tab bên dưới.
| Tùy chọn | Sao chép | Mô tả |
|---|---|---|
| -u, --unified | In ở định dạng hợp nhất, gộp cả tối đa ba dòng trước và sau các dòng thay đổi | |
| -c, --context | Định dạng ngữ cảnh, in riêng khối của tệp thứ nhất và khối của tệp thứ hai | |
| -i, --ignore-case | Bỏ qua khác biệt chữ hoa chữ thường | |
| -w, --ignore-all-space | Bỏ qua mọi khoảng trắng trong dòng | |
| -b, --ignore-space-change | Chỉ bỏ qua khác biệt về số lượng khoảng trắng | |
| -B, --ignore-blank-lines | Bỏ qua khác biệt về dòng trống | |
| -y, --side-by-side | In hai tệp cạnh nhau ở bên trái và bên phải | |
| -W, --widthNUM | Đặt chiều rộng khi in cạnh nhau. Giá trị mặc định là 130 cột | |
| --suppress-common-lines | Khi in cạnh nhau, bỏ các dòng giống nhau và chỉ in các dòng khác nhau | |
| -q, --brief | Chỉ in ra các tệp giống hay khác nhau. Nếu giống nhau thì không in gì | |
| -s, --report-identical-files | In một dòng báo rằng hai tệp giống nhau khi chúng giống nhau | |
| -r, --recursive | So sánh cả các tệp trong thư mục con |
| Tùy chọn | Sao chép | Mô tả |
|---|---|---|
| -U, --unifiedNUM | Đặt số dòng trước và sau được in kèm trong định dạng hợp nhất. Giá trị mặc định là 3 | |
| -N, --new-file | Coi tệp không có ở một phía là tệp rỗng | |
| -x, --excludePAT | Loại khỏi phép so sánh các tệp có tên khớp với mẫu | |
| -I, --ignore-matching-linesRE | Bỏ qua khác biệt nếu mọi dòng thay đổi đều khớp với biểu thức chính quy | |
| -Z, --ignore-trailing-space | Bỏ qua khoảng trắng ở cuối dòng | |
| -E, --ignore-tab-expansion | Bỏ qua khác biệt sinh ra do đổi tab thành khoảng trắng | |
| -a, --text | Coi mọi tệp là văn bản | |
| --strip-trailing-cr | Bỏ ký tự carriage return ở cuối dòng rồi mới so sánh | |
| --colorWHEN | Tô màu kết quả. WHEN là never, always hoặc auto | |
| -v, --version | In thông tin phiên bản |
🔲 Trình mô phỏng lệnh diff
Trong trình mô phỏng bên dưới, có thể tự gõ diff với các tệp ví dụ trong bài. Có thể lưu tệp vá bằng -u hoặc so sánh bằng -i -w -B và -rq, và nếu thêm một dòng vào config-new.conf rồi so sánh lại thì kết quả đã thay đổi sẽ hiện ra.
4️⃣ So sánh thư mục bằng diff -r
Khi cần so sánh nhiều tệp cùng lúc, chẳng hạn trước và sau khi triển khai các tệp của trang web, ghi tên thư mục thay cho tệp. Hai thư mục ví dụ site-v1 và site-v2 đều có index.html và thư mục css, còn about.html và contact.html chỉ có ở một phía.
diff site-v1 site-v2Only in site-v1: about.html
Only in site-v2: contact.html
Common subdirectories: site-v1/css and site-v2/css
diff site-v1/index.html site-v2/index.html
2,3c2,3
< <p>Version 1</p>
< <a href="about.html">About</a>
---
> <p>Version 2</p>
> <a href="contact.html">Contact</a>Khi so sánh thư mục mà không có tùy chọn, tệp chỉ có ở một phía hiện ra bằng dòng [Only in], thư mục con chỉ hiện ra bằng dòng [Common subdirectories], và các tệp trong thư mục con không được so sánh. Với index.html, có cùng tên ở cả hai thư mục, khác biệt được in bên dưới dòng [diff site-v1/index.html site-v2/index.html]. Thêm -r thì cả giá trị màu đã đổi trong style.css ở thư mục css cũng được in ra.
diff -r site-v1 site-v2Only in site-v1: about.html
Only in site-v2: contact.html
diff -r site-v1/css/style.css site-v2/css/style.css
2c2
< h1 { color: #222; }
---
> h1 { color: #0a58ca; }
diff -r site-v1/index.html site-v2/index.html
2,3c2,3
< <p>Version 1</p>
< <a href="about.html">About</a>
---
> <p>Version 2</p>
> <a href="contact.html">Contact</a>Với thư mục có nhiều tệp, trước hết kiểm tra danh sách tệp thay đổi bằng -rq, rồi chỉ so sánh lại những tệp cần thiết bằng diff.
diff -rq site-v1 site-v2Only in site-v1: about.html
Only in site-v2: contact.html
Files site-v1/css/style.css and site-v2/css/style.css differ
Files site-v1/index.html and site-v2/index.html differ🔢 FAQ & nội dung đề xuất
Linux · Văn bản
Lệnh grep trên Linux
Cách dùng grep để tìm và in ra chỉ những dòng chứa chuỗi mong muốn trong tệp văn bản như tệp nhật ký.
Linux · Văn bản
Lệnh sort trên Linux: sắp xếp tệp
Các tùy chọn và ví dụ của sort để sắp xếp nội dung tệp theo bảng chữ cái, tăng dần hoặc giảm dần.
Linux · Văn bản
Lệnh uniq trên Linux
Cách dùng uniq để giữ lại một dòng trong các dòng trùng nhau và đếm số lần lặp bằng -c.
ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.