Grep? Ripgrep? Silver Searcher? Công cụ nào tốt để tìm kiếm văn bản trong tệp?

Tác giả Starlink, T.Mười 31, 2025, 09:00:12 CHIỀU

« Chủ đề trước - Chủ đề tiếp »

0 Thành viên và 1 Khách đang xem chủ đề.

Grep đã chết. Ripgrep.

Grep là công cụ tìm kiếm tệp toàn văn bản trên dòng lệnh đã được thiết lập. Tuy nhiên, vẫn có các lựa chọn thay thế, chẳng hạn như ripgrep, ag và sift. Nhưng liệu bạn có nên chuyển đổi không, và nếu có, công cụ tìm kiếm nào nên là lựa chọn hàng đầu của bạn? Hãy cùng tìm hiểu.


1. Grep hoạt động như thế nào?

Grep là một trong những công cụ Linux hữu ích nhất hiện có, và nó đã như vậy trong nửa thế kỷ. Tên của nó là viết tắt của Global Regular Expression Print, nhưng thực ra là dựa theo một lệnh ed cũ: g/re/p. Lệnh này rất hiệu quả trong việc tìm kiếm văn bản, đặc biệt là khi sử dụng ngôn ngữ biểu thức chính quy mạnh mẽ.

Bạn có thể bắt đầu một cách đơn giản bằng cách tìm kiếm văn bản cơ bản:

Mã nguồn [Chọn]
grep 'TODO' journal.md   
Và cuối cùng, bạn sẽ tạo ra được những mẫu kết hợp phức tạp:

Mã nguồn [Chọn]
grep -E "^([0-9]{4})-([0-9]{2})-([0-9]{2})" dates.txt   
Ví dụ này cho thấy sức mạnh thô sơ của grep: nó sử dụng biểu thức chính quy mở rộng để khớp các dòng bắt đầu bằng một ngày ISO đơn giản, chẳng hạn như 2025-10-26. Bạn cũng có thể sử dụng grep trong các pipeline của mình, rất hiệu quả. Ví dụ: lệnh này sẽ xuất các dòng từ nhật ký Apache, theo thời gian thực, nếu máy chủ gửi trạng thái "chưa sửa đổi":

Mã nguồn [Chọn]
tail -f /var/log/apache2/access_log | grep '" 304'   
Và một tính năng tuyệt vời cuối cùng của grep: tìm kiếm đệ quy. Chạy lệnh "grep -r pattern" sẽ tìm kiếm tất cả các tệp trong thư mục hiện tại và các thư mục bên dưới, in ra từng kết quả khớp. Điều này khiến grep trở thành một công cụ hoàn hảo để tìm các tệp chứa bất kỳ mẫu văn bản nào bạn cần tìm kiếm:

Mã nguồn [Chọn]
grep -ri todo   
2. Ripgrep có chức năng gì tốt hơn?

grep rất phổ biến và có lẽ đã làm được nhiều hơn bất kỳ chương trình nào khác để chứng minh sức mạnh của Unix: các chương trình tập trung, làm việc cộng tác, giao tiếp bằng cách truyền dữ liệu văn bản. Vậy tại sao phải tìm kiếm ở nơi khác?

ripgrep là một lựa chọn thay thế phổ biến, hiện đại cho grep, và là một trong những nâng cấp tốt nhất cho lệnh mặc định mà bạn có thể thực hiện. Bạn có thể cài đặt nó với nhiều trình quản lý gói khác nhau, bằng cách sử dụng lệnh như brew install ripgrep, sudo apt-get install ripgrep, sudo dnf install ripgrep, hoặc lệnh phù hợp với hệ thống của bạn. Sau khi cài đặt, bạn sẽ chạy nó dưới dạng rg (không phải ripgrep), sử dụng cách tiếp cận tương tự như grep. Ví dụ: để tìm tất cả các tiêu đề trong một tệp markdown:

Mã nguồn [Chọn]
rg '^#' README.md   
Phiên bản đầu tiên của ripgrep ra mắt vào năm 2016 và tận dụng lợi thế của ngôn ngữ lập trình Rust còn khá mới. Nhìn chung, nhờ một số tối ưu hóa tuyệt vời của công cụ biểu thức chính quy trong Rust, ripgrep nhanh hơn các lựa chọn thay thế, đặc biệt là grep, vốn có thể chậm hơn tới mười lần.

Bạn có thể không nhận thấy lợi ích về tốc độ này khi sử dụng hàng ngày. Nhưng nếu bạn đang chạy các tìm kiếm dài hạn hơn—đặc biệt là các tìm kiếm đệ quy, trên nhiều tệp, với các mẫu phức tạp hơn—ripgrep có thể mang lại lợi ích lớn. Tìm kiếm đệ quy là mặc định của ripgrep, đến mức lệnh sau là tất cả những gì bạn cần để tìm kiếm một mẫu trong tất cả các tệp bên trong và bên dưới thư mục hiện tại:

Mã nguồn [Chọn]
rg PATTERN   
Để có một phép so sánh sơ bộ, tôi đã thực hiện một bài kiểm tra đơn giản (không quá khắt khe) bằng cách sử dụng một thư mục chứa khoảng 40.000 tệp. Lệnh grep mất 30 giây để hoàn tất, trong khi ripgrep chỉ mất chưa đến 1 giây. Kết quả này chắc chắn sẽ khác nhau tùy thuộc vào một số yếu tố, nhưng ripgrep chắc chắn hoạt động tốt hơn trong quá trình sử dụng hàng ngày của tôi.


Một lý do khiến ripgrep nhanh như vậy là nhờ mô hình đa luồng, chạy tìm kiếm đệ quy song song. Một tác dụng phụ thú vị là bạn (có thể) sẽ thấy kết quả theo thứ tự khác nhau mỗi lần chạy cùng một tìm kiếm. Nếu gặp vấn đề này, hãy sử dụng tùy chọn --sort path.

Nhưng ưu điểm của ripgrep không chỉ nằm ở tốc độ; chương trình còn có một bộ tính năng phong phú. Một trong những tính năng đơn giản nhất là hỗ trợ một loạt các tùy chọn lọc dành riêng cho từng ngôn ngữ, ví dụ:

Mã nguồn [Chọn]
rg --type sh 'todo'   
Thao tác này sẽ thực hiện tìm kiếm đệ quy từ thư mục hiện tại, chỉ tìm kiếm trong các tập lệnh shell mẫu "todo". Công cụ này hỗ trợ một danh sách dài các loại tệp, bạn có thể hiển thị bằng tùy chọn --type-list:


Lệnh ripgrep có bản chất đệ quy, nhưng ngay cả hành vi này cũng có thể được kiểm soát bằng tùy chọn --max-depth. Chỉ cần chạy lệnh rg --max-depth 1 PATTERN và lệnh tìm kiếm của bạn sẽ mô phỏng lệnh grep cơ bản, giới hạn ở các tệp trong thư mục hiện tại.

Phù hợp với nhiều chương trình hiện đại, ripgrep hỗ trợ git theo nghĩa là nó sẽ đọc tệp .gitignore và bỏ qua các tệp tương tự. Điều này chỉ xảy ra ở chế độ đệ quy, và có rất nhiều tùy chọn cấu hình cho phép bạn tinh chỉnh chức năng này.

ripgrep còn có nhiều tính năng hơn nữa. Nó có thể bỏ qua các tệp lớn hơn một kích thước nhất định (--max-filesize), hiển thị thông tin tóm tắt (--stats), sử dụng tìm kiếm chữ hoa/thường thông minh (dựa trên chữ cái trong mẫu của bạn) và tìm kiếm bên trong các tệp gzip.

3. Có những công cụ tìm kiếm đầu cuối nào khác không?

Mặc dù grep được coi là công cụ tìm kiếm mặc định và ripgrep là lựa chọn thay thế phổ biến nhất, nhưng vẫn có một số chương trình khác đáng để thử.

3.1. Ack

ack là một công cụ tương tự, tương thích phần lớn với grep, được viết bằng Perl. Một lần nữa, mặc định nó là đệ quy, rất tiện lợi. Nó cũng hoạt động tương tự ripgrep, kiểm tra các tệp mà nó nhận dạng được—theo loại—nhưng bỏ qua các tệp khác. Tuy nhiên, điều này không áp dụng cho các tệp được khớp với tệp .gitignore, mặc dù ack sẽ bỏ qua bất kỳ thư mục .git nào.

ack có tùy chọn -f khá thú vị, cho phép in đường dẫn của tất cả các tệp mà nó sẽ tìm kiếm mà không cần phải thực sự tìm kiếm chúng. Điều này có vẻ không hữu ích lắm, nhưng bạn có thể tận dụng các tính năng khác của ack bằng cách sử dụng nó để in danh sách tất cả các tệp (tương tự như "find .") hoặc tất cả các tệp cùng loại. Tùy chọn này sẽ hoạt động cùng với .gitignore, vì vậy đây là một cách hữu ích để tìm tệp trong kho lưu trữ mã nguồn.

Theo kinh nghiệm của tôi, ack nhanh hơn grep, nhưng không nhanh bằng ripgrep.

3.2. The Silver Searcher

Lệnh ag chạy một chương trình có tên là The Silver Searcher, phát ra cụm từ "Silver Surfer" và tham chiếu đến ký hiệu hóa học của bạc.

ag là một lựa chọn thay thế rất đáng tin cậy cho ripgrep. Nó không nhanh bằng rg theo kinh nghiệm sử dụng của tôi, nhưng cũng gần như vậy. Sự khác biệt không quá lớn đến mức bạn khó nhận ra, trừ khi bạn đang chạy thử nghiệm chuẩn hoặc thực hiện các tìm kiếm rất phức tạp.

Nhưng ag có thể thực hiện nhiều chức năng giống như rg: nó chấp nhận các tệp .gitignore, khớp với các dòng mới, tìm kiếm bên trong các tệp nhị phân và có thể in số liệu thống kê tóm tắt.

3.3. Sift

Sift là một công cụ tìm kiếm văn bản khác, lần này được viết bằng Go. Mặc định, nó có tính năng đệ quy, với tùy chọn tắt. Trong khi đầu ra của rg nhóm kết quả theo tệp, sift in ra đường dẫn đầy đủ trước mỗi kết quả khớp. Cách tiếp cận này hy sinh khả năng đọc của con người để máy có thể đọc được, vì vậy theo mặc định, nó có thể dễ dàng hơn cho việc viết mã.

Giống như ag, sift nhanh, nếu không muốn nói là nhanh bằng rg. Mặc định, nó sẽ tìm kiếm càng nhiều tệp càng tốt, bao gồm cả tệp nhị phân và các tệp được đề cập trong .gitignore. Tuy nhiên, bạn có thể bỏ qua bất kỳ tập hợp tệp nào bằng cách sử dụng tùy chọn --binary-skip và --git.

Sift không có trang hướng dẫn, theo tôi đây là một nhược điểm, mặc dù nó cung cấp thông tin hữu ích với tùy chọn --help.

Nếu bạn vẫn đang dùng grep, bất kỳ công cụ nào trong số này cũng sẽ mang lại cảm giác như một bản nâng cấp đáng kể. Ripgrep là công cụ yêu thích của tôi vì nó rất tinh tế và danh sách dài các tính năng cho phép thực hiện nhiều loại tìm kiếm mạnh mẽ khác nhau. Tốc độ tuyệt vời của nó, so với grep, phải tận mắt chứng kiến mới tin được.

Luôn tuyệt vời khi có các lựa chọn thay thế: một hệ sinh thái mã nguồn mở với sự cạnh tranh lành mạnh sẽ tạo ra phần mềm tốt hơn về mọi mặt. Tuy nhiên, không có nhiều điểm khác biệt giữa các công cụ này khi sử dụng thông thường, ngoài ngôn ngữ lập trình. ripgrep chắc chắn là nhanh nhất (chỉ cần) và có lẽ là lựa chọn tốt nhất của bạn, trừ khi bạn cần một số tùy chọn rất cụ thể.

Tin đáng mừng là ripgrep vẫn đang trong quá trình phát triển tích cực, gần đây nhất là phiên bản 15.0.0 được phát hành vào tháng 10. ack vẫn đang được phát triển, với tần suất ít hơn một chút, trong khi sift và ag đều đã ngừng cập nhật.