Lệnh Grep trong Linux (Tìm văn bản trong tệp)

By | 14 January, 2020

Lệnh grep viết tắt của “global regular expression print” là một trong những lệnh mạnh nhất và thường được sử dụng trong Linux.

Grep tìm kiếm một hoặc nhiều tệp đầu vào cho các dòng khớp với một mẫu nhất định và ghi từng dòng khớp vào đầu ra tiêu chuẩn. Nếu không có tệp nào được chỉ định, grep đọc từ đầu vào tiêu chuẩn, thường là đầu ra của lệnh khác.

Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách sử dụng lệnh grep thông qua các ví dụ thực tế và giải thích chi tiết về các tùy chọn grep GNU phổ biến nhất .

Cú pháp lệnh Grep

Trước khi đi vào cách sử dụng lệnh grep, hãy bắt đầu bằng cách xem lại cú pháp cơ bản.

Biểu thức grep có dạng sau:

grep [OPTIONS] PATTERN [FILE...]

Các mục trong ngoặc vuông là tùy chọn.

  • OPTIONS– Không hoặc nhiều tùy chọn. Grep cung cấp một số tùy chọn kiểm soát hành vi của nó.
  • PATTERN – Mẫu tìm kiếm.
  • FILE – Không hoặc nhiều tên tệp đầu vào.

Để có thể tìm kiếm tệp, người dùng chạy lệnh phải có quyền truy cập đọc vào tệp.

Cách sử dụng grep để Tìm kiếm Chuỗi trong Tệp

Cách sử dụng cơ bản nhất của lệnh grep là tìm kiếm một chuỗi (văn bản) trong một tệp.

Ví dụ: để hiển thị các dòng từ file /etc/passwd chứa chuỗi bash bạn có thể sử dụng lệnh sau:

grep bash /etc/passwd

Đầu ra sẽ trông giống như thế này:

root:x:0:0:root:/root:/bin/bash
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

Nếu chuỗi bao gồm khoảng trắng, bạn cần đặt nó trong dấu ngoặc kép đơn hoặc kép:

grep "Gnome Display Manager" /etc/passwd

Đảo ngược Match (không bao gồm)

Để hiển thị các dòng không khớp với mẫu, sử dụng tùy chọn -v (hoặc --invert-match).

Ví dụ: để hiển thị các dòng từ file /etc/passwd không chứa chuỗi nologin , bạn có thể sử dụng lệnh sau:

grep -v nologin /etc/passwd

Output:

root:x:0:0:root:/root:/bin/bash
colord:x:124:124::/var/lib/colord:/bin/false
git:x:994:994:git daemon user:/:/usr/bin/git-shell
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

Cách sử dụng Grep để tìm kiếm chuỗi trong đầu ra lệnh

Thay vì chỉ định các tệp đầu vào, bạn có thể chuyển đầu ra của lệnh khác sang grep, sau đó chỉ hiển thị các dòng khớp với một mẫu nhất định.

Ví dụ: để tìm hiểu các process đang chạy trên hệ thống của bạn với tư cách là người dùng www-data bạn có thể sử dụng lệnh ps sau :

ps -ef | grep www-data

Output:

www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
root     18272 17714  0 16:00 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn www-data
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

Bạn cũng có thể xâu chuỗi nhiều pipe theo lệnh. Như bạn có thể thấy trong đầu ra ở trên cũng có một dòng chứa process grep. Nếu bạn không muốn dòng đó được hiển thị, hãy chuyển đầu ra grep theo một cách khác như hiển thị bên dưới.

ps -ef | grep www-data | grep -v grep

Output:

www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
root     18272 17714  0 16:00 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn www-data
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

Để tìm kiếm đệ quy một mẫu, hãy sử dụng tùy chọn -r (hoặc --recursive). Điều này sẽ tìm kiếm thông qua tất cả các tệp trong thư mục được chỉ định, bỏ qua các symbolic link. Để theo tất cả các symbolic link , sử dụng tùy chọn -R (hoặc --dereference-recursive).

Trong ví dụ sau, tôi đang tìm kiếm chuỗi hocdevops.com trong tất cả các tệp trong thư mục /etc:

grep -r hocdevops.com /etc

Lệnh sẽ in các dòng khớp với tiền tố của đường dẫn đầy đủ đến tệp.

/etc/hosts:127.0.0.1 node2.hocdevops.com
/etc/nginx/sites-available/hocdevops.com:    server_name hocdevops.com   www.hocdevops.com;

Nếu bạn sử dụng -r thay cho tùy chọn -Rgrep sẽ theo tất cả các liên kết tượng trưng (symbolic link):

grep -R hocdevops.com /etc

Lưu ý dòng cuối cùng của đầu ra. Dòng đó không được in trong ví dụ trên vì các tệp trong thư mục sites-enabled của Nginx là các liên kết tượng trưng (symbolic link) đến các tệp cấu hình bên trong thư mục sites-available.

/etc/hosts:127.0.0.1 node2.hocdevops.com
/etc/nginx/sites-available/hocdevops.com:    server_name hocdevops.com   www.hocdevops.com;
/etc/nginx/sites-enabled/hocdevops.com:    server_name hocdevops.com   www.hocdevops.com;

Chỉ hiển thị tên tệp

Để chặn đầu ra grep mặc định và chỉ in tên của các tệp chứa mẫu phù hợp, bạn có thể sử dụng tùy chọn -l(hoặc --files-with-matches).

Ví dụ: để tìm kiếm trong tất cả các tệp kết thúc bằng .conftrong thư mục làm việc hiện tại và chỉ in tên của các tệp chứa loại chuỗi hocdevops.com :

grep -l hocdevops.com *.conf

Đầu ra sẽ trông giống như thế này:

tmux.conf
haproxy.conf

Tùy chọn -l thường được sử dụng kết hợp với các tùy chọn đệ quy -R:

grep -Rl hocdevops.com /tmp

Theo mặc định, lệnh grep tìm kiếm cả các trường hợp đặc biệt. Điều này có nghĩa là các ký tự chữ hoa và chữ thường được coi là đặc biệt.

Để bỏ qua khi tìm kiếm, sử dụng tùy chọn -i (hoặc --ignore-case).

Ví dụ: khi tìm kiếm Zebra mà không có tùy chọn nào, lệnh sau sẽ không hiển thị bất kỳ đầu ra nào, tức là có các dòng khớp:

grep Zebra /usr/share/words

Nhưng nếu bạn thực hiện tìm kiếm không phân biệt chữ hoa bằng cách sử dụng tùy chọn -i, nó sẽ khớp cả chữ in hoa và chữ thường:

grep -i Zebra /usr/share/words

Xác định chữ Zebra sẽ khớp với “zebra”, “ZEbrA” , hoặc bất kỳ sự kết hợp nào khác của chữ in hoa và chữ thường cho chuỗi đó.

zebra
zebra's
zebras

Tìm kiếm đầy đủ

Khi tìm kiếm trong các trang web, grep cũng sẽ in các dòng trong đó.

grep gnu /usr/share/words

Output:

cygnus
gnu
interregnum
lgnu9d
lignum
magnum
magnuson
sphagnum
wingnut

Để chỉ trả về những dòng có chuỗi được chỉ định là toàn bộ từ (được bao quanh bởi các ký tự không phải từ), hãy sử dụng tùy chọn -w(hoặc --word-regexp).

Nếu bạn chạy cùng một lệnh như trên, bao gồm tùy chọn -w,lệnh grepsẽ chỉ trả về những dòng gnu chỉ bao gồm dưới dạng một từ riêng biệt.

grep -w gnu /usr/share/words

Output:

gnu

Hiển thị số dòng

Để hiển thị số lượng dòng có chứa chuỗi khớp với mẫu, sử dụng tùy chọn -n(hoặc --line-number). Khi sử dụng tùy chọn này, grep sẽ in các kết quả khớp với đầu ra tiêu chuẩn có tiền tố với số dòng được tìm thấy trên đó.

Ví dụ: để hiển thị các dòng từ file /etc/services chứa chuỗi có tiền tố bash với số dòng phù hợp, bạn có thể sử dụng lệnh sau:

grep -n 10000 /etc/services

Đầu ra bên dưới cho chúng ta thấy rằng các kết quả khớp được tìm thấy trên các dòng 10423 và 10424.

10423:ndmp            10000/tcp
10424:ndmp            10000/udp

Đếm các trường hợp match

Để in một số dòng phù hợp với đầu ra tiêu chuẩn, sử dụng tùy chọn -c(hoặc --count).

Trong ví dụ dưới đây, tôi đang đếm số lượng account có shell trong /usr/bin/zsh.

grep -c '/usr/bin/zsh' /etc/passwd

Output:

4

Tìm kiếm nhiều chuỗi

Hai hoặc nhiều mẫu tìm kiếm có thể được nối bằng toán tử OR |.

Theo mặc định, grep diễn giải mẫu như một biểu thức chính quy cơ bản trong đó các ký tự meta như |không có tác dụng do đó dấu gạch chéo ngược phải được sử dụng.

Trong ví dụ dưới đây, tôi đang tìm kiếm tất cả các lần xuất hiện của các từ fatalerrorvà critical trong file log lỗi Nginx:

grep 'fatal\|error\|critical' /var/log/nginx/error.log

Nếu bạn sử dụng tùy chọn biểu thức chính quy mở rộng -E(hoặc --extended-regexp) thì toán tử |sẽ không cần \, như hiển thị bên dưới:

grep -E 'fatal|error|critical' /var/log/nginx/error.log

Quiet Mode

Tùy chọn -q(hoặc --quiet) cho grep không in ra terminal (đầu ra tiêu chuẩn). Nếu quá trình tìm kiếm tìm thấy dữ liệu, lệnh sẽ thoát với trạng thái 0. Điều này hữu ích khi sử dụng grep trong các tập lệnh shell nơi bạn muốn kiểm tra xem một tệp có chứa một chuỗi hay không và thực hiện một hành động nhất định tùy thuộc vào kết quả.

Dưới đây là một ví dụ về việc sử dụng grep trong quiet mode  làm lệnh kiểm tra trong câu lệnh if :

if grep -q PATTERN filename
then
    echo pattern found
else
    echo pattern not found
fi

Biểu thức chính quy cơ bản

GNU Grep có hai bộ tính năng biểu thức chính quy, Cơ bản và Mở rộng. Theo mặc định, grep sử dụng biểu thức chính quy cơ bản.

Khi được sử dụng trong chế độ biểu thức chính quy cơ bản, tất cả các ký tự khác ngoại trừ các ký tự meta, các biểu thức chính quy khớp với chính chúng. Dưới đây là danh sách các ký tự meta được sử dụng phổ biến nhất:

  • Sử dụng ^ (dấu mũ) để khớp với biểu thức ở đầu một dòng. Trong ví dụ sau, chuỗi ^kangaroo sẽ chỉ khớp nếu nó xảy ra ở ngay đầu dòng.
grep "^kangaroo" file.txt
  • Sử dụng $ (đô la) để khớp với biểu thức ở cuối dòng. Trong ví dụ sau, chuỗi kangaroo$ sẽ chỉ khớp nếu nó xảy ra ở cuối dòng.
grep "kangaroo$" file.txt
  • Sử dụng . (dấu chấm) để khớp với bất kỳ ký tự đơn nào. Ví dụ: để khớp với bất cứ thứ gì bắt đầu kan sau đó có hai ký tự và kết thúc bằng chuỗi roo, bạn có thể sử dụng mẫu sau:
grep "kan..roo" file.txt
  • Sử dụng [ ] (ngoặc) để khớp với bất kỳ ký tự đơn nào được đặt trong ngoặc. Ví dụ: tìm các dòng có chứa accept hoặc accent, bạn có thể sử dụng mẫu sau:
grep "acce[np]t" file.txt
  • Sử dụng [^ ](ngoặc) để khớp với bất kỳ ký tự đơn nào được đặt trong ngoặc. Mẫu sau sẽ khớp với bất kỳ tổ hợp chuỗi nào có chứa co(any_letter_except_l)a, chẳng hạn như cocacobaltv.v., nhưng sẽ không khớp với các dòng chứa cola:
grep "co[^l]a" file.txt

Để sử dụng ký tự đặc biệt, hãy sử dụng \ (dấu gạch chéo ngược).

Biểu thức chính quy mở rộng

Để diễn giải mẫu dưới dạng biểu thức chính quy mở rộng, hãy sử dụng tùy chọn -E(hoặc --extended-regexp). Các biểu thức chính quy mở rộng bao gồm tất cả các ký tự meta cơ bản, cùng với các ký tự meta bổ sung để tạo các mẫu tìm kiếm phức tạp và mạnh mẽ hơn. Dưới đây là một số ví dụ:

  • Khớp và trích xuất tất cả các địa chỉ email từ một tệp nhất định:
grep -E -o "\b[A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" file.txt
  • Khớp và trích xuất tất cả các địa chỉ IP hợp lệ từ một tệp đã cho:
grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt

Tùy chọn -o được sử dụng để in chỉ chuỗi phù hợp.

Để in một số dòng cụ thể trước khi khớp dòng, sử dụng tùy chọn -B(hoặc --before-context).

Ví dụ: để hiển thị 5 dòng đầu trước khi khớp các dòng, bạn sẽ sử dụng lệnh sau:

grep -B 5 root /etc/passwd

Để in một số dòng cụ thể sau khi khớp dòng, sử dụng tùy chọn -A(hoặc --after-context).

Ví dụ: để hiển thị năm dòng sau các dòng khớp, bạn sẽ sử dụng lệnh sau:

grep -A 5 root /etc/passwd

Phần kết luận

Lệnh grep Giúp cho bạn tìm kiếm trong các file một cách dễ dàng. Nếu bạn muốn tìm hiểu nhiều hơn nữa về Grep, truy cập trang Hướng dẫn sử dụng của Grep .

Nếu bạn có bất kỳ câu hỏi hoặc phản hồi, hãy để lại nhận xét.

Leave a Reply

avatar
  Subscribe  
Notify of