Linux: 3 lệnh quan trọng để xử lý dữ liệu text

Linux: 3 lệnh quan trọng để xử lý dữ liệu text
Photo by Pixabay from Pexels

Để làm việc với dữ liệu text, có lẽ nhiều người đã từng sử dụng grep, sed, hay awk. Tuy nhiên, việc thành thạo những lệnh này cũng không đơn giản. Trong bài viết này, tôi sẽ trình bày những hiểu biết của mình về các sử dụng 3 lệnh trên. Nếu vẫn còn loay hoay với những lệnh này thì đây là bài viết dành cho bạn. (Còn thành thạo rồi thì thôi :D)

Trước khi đi vào nội dung chi tiết, tôi nhắc lại vài điểm cơ bản về nguồn gốc tên các lệnh:

  1. grep: được đặt tên từ lệnh g/re/p (globally search for a regular expression and print matching lines) của ed (nguồn: trust me, bro). ed là một line editor được phát triển cho UNIX và vẫn còn tồn tại đến ngày nay (mặc dù hầu như không còn được sử dụng).
  2. sed: được đặt tên theo cách nó hoạt động, stream editor.
  3. awk: tên lệnh này được ghép từ chữ cái đầu của tên các tác giả (Aho, Weinberger, and Kernighan). Trong những người này, có lẽ Kernighan là cái tên quen thuộc hơn cả. Ông là tác giả chính của cuốn sách “The C Programming Language” kinh điển.

Trong nội dung bài viết này, tôi sử dụng file excuses.txt (nội dung lấy từ trang http://programmingexcuses.com/) làm ví dụ minh họa. File được lưu trữ ở đây

grep

Lệnh grep được dùng khi cần tìm kiếm từ nào đó:

$ grep test excuses.txt
I broke that deliberately to do some testing
I can't test everything
I must have been stress testing our production server
It can't be broken, it passes all unit tests
It works, but it's not been tested
Management insisted we wouldn't need to waste our time writing unit tests
That code seemed so simple I didn't think it needed testing
The unit test doesn't cover that eventuality

Nếu cụm từ tìm kiếm có chứa dấu cách, cần phải sử dụng dấu nháy. Ví dụ:

$ grep "a feature" excuses.txt
Actually, that's a feature

Lệnh grep có thể nhận tùy chọn -i để không phân biệt chữ cái hoa/thường. Ngoài ra, lệnh này có thể dùng ký tự đại diện trong tên file để tìm kiếm trên nhiều file khác nhau:

$ grep -i string *.txt

Cũng có thể sử dụng regular expression để tìm kiếm bằng cách thêm -E hoặc dùng lệnh egrep:

$ grep -E "[A-Z]{3,}" excuses.txt
Oh, you said you DIDN'T want that to happen?
THIS can't be the source of THAT
The WYSIWYG must have produced an invalid output
The third party API is not responding
$ egrep "[A-Z]{3,}" excuses.txt
Oh, you said you DIDN'T want that to happen?
THIS can't be the source of THAT
The WYSIWYG must have produced an invalid output
The third party API is not responding

Lệnh dưới đây sẽ tìm kiếm tất cả các cụm từ “feature” đồng thời in ra kết quả dòng tiếp theo của nó:

$ grep feature -A 1 excuses.txt
Actually, that's a feature
Did you check for a virus on your system?
--
That feature was slated for phase two
That feature would be outside of the scope
That important email must have been marked as spam
--
The project manager said no one would want that feature
The project manager told me to do it that way

Nếu muốn in ra nhiều dòng hơn, chỉ cần thay đổi con số trong lệnh trên. Để in ra các dòng phía trên, lệnh grep cũng có sẵn tùy chọn -B.

Lệnh grep cũng có thể kết hợp với các lệnh khác thành pipe

$ cat excuses.txt | grep feature
Actually, that's a feature
That feature was slated for phase two
That feature would be outside of the scope
The project manager said no one would want that feature

sed

Tôi thường dùng lệnh sed để thay một string thành string khác:

grep this excuses.txt | sed 's/this/that/g'
It's never shown unexpected behaviour like that before

Trong ví dụ trên, “this” sẽ được thay thế bằng “that” và in ra màn hình, /g trong câu lệnh là để thay thế toàn bộ các string.

Lệnh sed có thể thực hiện nhiều hành động phức tạp như:

  • Chỉ thay thế các string xuất hiện trong 10 dòng đầu tiên:
$ sed '1,10 s/this/that/g' excuses.txt
  • Chỉ thay thế đúng string xuất hiện ở lần thứ n:
$ sed 's/this/that/2' excuses.txt

Trong những ví dụ trên, kết quả của lệnh sed sẽ được in ra màn hình còn nội dung file gốc không thay đổi. Nếu muốn ghi đè nội dung vào file gốc, cần thêm tùy chọn -i:

$ sed -i 's/this/that/2' excuses.txt

Việc sử dụng -i để ghi đè file rất nguy hiểm. Có thể sử dụng grep để tìm kiếm các cụm từ phù hợp trước khi tiến hành thay thế để đảm bảo kết quả nhận được đúng như mong muốn.

awk

Lệnh awk cung cấp rất nhiều tính năng để làm việc với dữ liệu text. Tôi thường sử dụng awk với những dữ liệu có cấu trúc nhất định.

Khi awk xử lý dữ liệu, nó sẽ xử lý theo từng dòng và cắt text thành các string ngăn cách bởi FS (field separator – mặc định là dấu cách). Mỗi string được gọi là một field và được gán cho các biến $1, $2, … còn $0 chứa nội dung của cả dòng.

Cũng có thể áp dụng filter trong lệnh awk, ví dụ:

$ cat excuses.txt | awk '/feature/ { print NR " - " $0 }'
1 - Actually, that's a feature
88 - That feature was slated for phase two
89 - That feature would be outside of the scope
113 - The project manager said no one would want that feature

Tham số truyền cho lệnh awk sử dụng dấu nháy đơn.

  • Lệnh này chỉ xử lý các dòng có chữ “feature”
  • Sau đó sẽ xử lý theo những gì bên trong dấu ngoặc nhọn.
    • NR là đại diện cho số dòng của dòng hiện tại
    • Thêm dấu " - " để ngăn cách kết quả

Các biến mà awk cung cấp sẵn:

  • NR: (Number of Record) Số dòng hiện tại
  • NF: (Number of field) Số thứ tự của field
  • FS: field separator (mặc định là dấu cách)

Dưới đây là một ví dụ khác về việc xử lý dữ liệu có cấu trúc:

$ cat /etc/passwd | awk '/nologin/ { FS=":"; print $1 }'
bin
sys
man
lp
...

Cụ thể:

  • /nologin/: chỉ xử lý những dòng có chứa “nologin”
  • FS=": "; sử dụng dấu hai chấm : để ngăn cách thay vì dấu cách mặc định
  • print $1: in ra string đầu tiên (ngăn cách bởi dấu :)

Kết luận

Trên đây là những trường hợp điển hình về việc sử dụng các lệnh grep, sed, và awk. Đó chỉ là những trường hợp thông dụng và đơn giản. Nếu dùng lệnh man để tìm hiểu kỹ hơn về những lệnh này, chúng có thể được áp dụng cho những bài toán phức tạp hơn rất nhiều.

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.