Đọc và Xử Lý Văn Bản: grep, sed, awk và Bạn Bè

K
Kai··4 min read

Đây là nhóm công cụ làm nên sức mạnh của dòng lệnh Linux. Đúng triết lý Unix (Bài 0), mỗi cái làm tốt một việc — xem, lọc, cắt, sắp, đếm, biến đổi văn bản. Học riêng từng cái, rồi Bài 6 sẽ ghép chúng lại bằng pipe.

Tạo một file mẫu trong lab để thực hành:

cd /tmp
printf "alice 90 math\nbob 75 science\ncarol 88 math\ndave 75 math\nalice 95 science\n" > scores.txt

Xem nội dung: cat, less, head, tail

cat scores.txt        # in toàn bộ file ra màn hình
less scores.txt       # xem file dài có phân trang (q để thoát, / để tìm)
head -2 scores.txt    # 2 dòng đầu
tail -1 scores.txt    # dòng cuối

cat hợp file ngắn; file dài thì less (cuộn bằng mũi tên/Space, thoát bằng q). head/tail lấy vài dòng đầu/cuối.

Đặc biệt hữu ích khi gỡ lỗi: tail -f theo dõi file log theo thời gian thực, in ra mỗi dòng mới được ghi:

tail -f /var/log/syslog    # bám đuôi log, Ctrl+C để dừng

Lọc dòng: grep

grep in ra những dòng khớp một mẫu — công cụ bạn dùng nhiều nhất để tìm trong log và file:

grep math scores.txt        # các dòng chứa "math"
grep -i MATH scores.txt     # -i: không phân biệt hoa/thường
grep -v math scores.txt     # -v: nghịch đảo (dòng KHÔNG chứa "math")
grep -c math scores.txt     # -c: đếm số dòng khớp
grep -n math scores.txt     # -n: kèm số dòng
grep -r "TODO" /duong/dan   # -r: tìm đệ quy trong cả thư mục
alice 90 math
carol 88 math
dave 75 math

grep hiểu cả biểu thức chính quy (regex), ví dụ grep "^alice" scores.txt lọc dòng bắt đầu bằng "alice" (^ = đầu dòng).

Cắt cột: cut

Với dữ liệu có cột, cut lấy ra cột bạn cần:

cut -d ' ' -f1 scores.txt   # -d ' ' tách bằng dấu cách, -f1 lấy cột 1
alice
bob
carol
dave
alice

-d chỉ ký tự ngăn cách (delimiter), -f chỉ số cột. Hay dùng với file CSV (-d ',') hoặc /etc/passwd (-d ':').

Sắp xếp và lọc trùng: sort, uniq

sort scores.txt              # sắp theo thứ tự chữ cái
sort -k2 -n scores.txt       # -k2 theo cột 2, -n sắp theo SỐ (không phải chữ)
cut -d ' ' -f1 scores.txt | sort | uniq      # tên không trùng
cut -d ' ' -f1 scores.txt | sort | uniq -c   # đếm số lần mỗi tên xuất hiện

Lưu ý: uniq chỉ gộp các dòng trùng liền kề, nên gần như luôn phải sort trước. uniq -c đếm số lần lặp — mẫu sort | uniq -c | sort -rn rất hay dùng để xếp hạng (ví dụ IP xuất hiện nhiều nhất trong log).

Đếm: wc

wc scores.txt        # số dòng, số từ, số ký tự
wc -l scores.txt     # chỉ đếm dòng (-l)
 5 15 73 scores.txt

wc -l cực hay dùng để đếm: ví dụ grep error log | wc -l đếm số lỗi.

Biến đổi văn bản: sed

sed (stream editor) sửa văn bản theo luồng, phổ biến nhất là thay thế:

sed 's/math/TOAN/g' scores.txt    # thay "math" -> "TOAN" trên mọi dòng
alice 90 TOAN
bob 75 science
carol 88 TOAN
...

Cú pháp s/cũ/mới/g: s = substitute, g = global (mọi lần xuất hiện trên dòng, không chỉ lần đầu). Mặc định sed in ra kết quả chứ không sửa file gốc; thêm -i để sửa thẳng vào file (sed -i 's/.../.../g' file) — cẩn thận vì nó ghi đè.

Xử lý theo cột: awk

awk mạnh hơn cho dữ liệu cột: nó tách mỗi dòng thành các trường $1, $2... và cho bạn lọc, tính toán:

awk '{print $1, $2}' scores.txt          # in cột 1 và 2
awk '$2 > 80 {print $1, $2}' scores.txt   # chỉ dòng có cột 2 > 80
alice 90
carol 88
alice 95

$2 > 80 là điều kiện, {print ...} là hành động. awk còn cộng dồn, tính trung bình, đếm theo nhóm... — cả một ngôn ngữ nhỏ. Với người mới, nhớ "tách cột thành $1 $2 ... rồi lọc/in" là đủ dùng phần lớn.

Khi nào dùng cái nào: grep để lọc dòng theo mẫu; cut để lấy cột đơn giản; sed để thay thế/biến đổi text; awk khi cần xử lý theo cột có điều kiện/tính toán. Chồng lấn nhau, nhưng đây là điểm mạnh của mỗi cái.

🧹 Dọn dẹp

rm -f scores.txt

Tổng kết

Bạn có một bộ công cụ xử lý văn bản: cat/less/head/tail (xem, kèm tail -f theo dõi log), grep (lọc dòng), cut (lấy cột), sort/uniq (sắp + lọc trùng), wc (đếm), sed (thay thế), awk (xử lý theo cột). Mỗi cái nhỏ và chuyên một việc.

Sức mạnh thật sự đến khi ghép chúng lại: đầu ra của cái này thành đầu vào của cái kia. Bài 6 giải thích cơ chế đó — pipe và redirect — cùng ba luồng dữ liệu stdin/stdout/stderr đứng sau.