sed (stream editor) là công cụ biến đổi văn bản theo dòng mạnh nhất trong bộ Unix cơ bản. Hầu hết lập trình viên biết đúng một câu lệnh: sed 's/cũ/mới/'. Nhưng sed làm được nhiều hơn thế rất nhiều — chọn dòng theo điều kiện, xoá, chèn, dùng nhóm bắt để sắp xếp lại dữ liệu. Bài này (phần 3 loạt Unix) chạy sed thật trên một file cấu hình mẫu để mở khoá những tính năng đó, và cảnh báo một cái bẫy khiến vô số script "chạy trên máy tôi" nhưng hỏng trên máy khác: sed -i.
Lệnh cốt lõi: s/cũ/mới/cờ
Cấu trúc quen thuộc s/mẫu/thay/cờ. Điều nhiều người không để ý: mặc định nó chỉ thay lần đầu tiên trên mỗi dòng. Các cờ đổi hành vi:
sed "s/port/cong/" # chỉ lần ĐẦU mỗi dòng
sed "s/port/cong/g" # g = mọi lần trên dòng
sed "s/aaa/X/2" # chỉ lần thứ 2
sed "s/hello/hi/gI" # I = không phân biệt hoa/thường (g = toàn bộ)
Một mẹo quan trọng: dấu phân cách đổi được. Nếu mẫu chứa dấu / (như đường dẫn), viết s#/var/log#/tmp# thay vì phải thoát từng dấu \/. sed nhận ký tự ngay sau s làm dấu phân cách.

Hình 1: Lệnh s/// với cờ g/N/I; địa chỉ chọn dòng (/mẫu/, số dòng, khoảng); nhóm bắt \1 \2; và bẫy sed -i khác nhau giữa GNU (Linux) và BSD (macOS).
Địa chỉ: chỉ tác động lên dòng bạn chọn
Đây là sức mạnh bị bỏ quên nhất của sed. Trước mỗi lệnh, bạn đặt một địa chỉ giới hạn dòng nào bị tác động: một số dòng, một /mẫu/, hay một khoảng. Chạy thật trên file cấu hình:

Hình 2: Chạy thật — cờ g/2/gI cho kết quả khác nhau; /debug/ s/true/false/ chỉ đổi dòng debug (port giữ nguyên); /^#/d xoá dòng comment; nhóm bắt đảo host=localhost → localhost <- host; -n "2,3p" in chọn lọc; sed -i sửa file tại chỗ.
/debug/ s/true/false/: chỉ dòng chứadebugbị đổitrue→false; các dòngportgiữ nguyên. Không có địa chỉ thìsedáp lệnh lên mọi dòng — địa chỉ cho phép nhắm chính xác./^#/d: lệnhd(delete) kết hợp địa chỉ/^#/xoá mọi dòng bắt đầu bằng#— cách gọn nhất để lọc comment khỏi file cấu hình.-n "2,3p":-ntắt in mặc định,pin dòng được chọn; kết hợp2,3(khoảng dòng) biếnsedthành công cụ trích dòng nhưgrep/head.
Nhóm bắt: sắp xếp lại dữ liệu
Với -E (ERE, như bài grep), bạn dùng nhóm bắt (...) và tham chiếu \1 \2 trong phần thay để sắp xếp lại:
echo "host=localhost" | sed -E "s/([a-z]+)=(.+)/\2 <- \1/"
# -> localhost <- host
([a-z]+) bắt key, (.+) bắt value, rồi ghép lại theo thứ tự đảo. Đây là cách sed làm được những biến đổi cấu trúc, không chỉ thay chuỗi đơn giản — ví dụ đổi định dạng ngày 2026-09-22 → 22/09/2026 bằng ba nhóm bắt.
Cái bẫy sed -i: Linux khác macOS
sed -i sửa file tại chỗ (in-place) thay vì in ra màn hình — cực tiện, nhưng đây là nguồn của một lỗi kinh điển khi script chạy trên nhiều máy:
- GNU sed (Linux):
sed -i "s/a/b/" file—-ikhông cần đối số. - BSD sed (macOS):
sed -i "s/a/b/" filebáo lỗi — BSD đòi-iphải có đối số hậu tố sao lưu, đúng làsed -i "" "s/a/b/" file(chuỗi rỗng nghĩa là không sao lưu).
Script viết trên Linux dùng sed -i "..." sẽ hỏng trên macOS với thông báo khó hiểu, và ngược lại. Cách viết chạy được cả hai: sed -i.bak "s/a/b/" file — luôn tạo một bản sao .bak (cả GNU lẫn BSD đều hiểu -i.bak). Nếu không muốn giữ .bak, xoá nó sau, hoặc tách nhánh theo hệ điều hành.
Đánh đổi cần cân nhắc
sed -i không có "undo" — luôn thử trước khi sửa tại chỗ. Chạy lệnh không -i trước để xem kết quả in ra màn hình, kiểm đúng rồi mới thêm -i. Một mẫu regex sai với -i có thể phá hỏng file cấu hình sản xuất trong tích tắc. Thói quen tốt: sed -i.bak để luôn có bản lùi.
sed xử lý theo dòng — không hợp cho dữ liệu nhiều dòng hay có cấu trúc. Sửa JSON, XML, YAML bằng sed là cái bẫy: một trường có thể trải nhiều dòng, thứ tự thay đổi, và regex không hiểu cấu trúc lồng nhau. Dùng công cụ hiểu định dạng (jq cho JSON, yq cho YAML) thay vì sed cho dữ liệu có cấu trúc.
Khi logic phức tạp, awk hoặc script thật rõ hơn. sed với nhiều lệnh nối bằng ;, nhãn, và vòng lặp trở nên khó đọc rất nhanh. Nếu bạn thấy mình viết sed dài hơn hai ba lệnh, awk (bài sau) hoặc một script Python/Perl thường dễ bảo trì hơn — sự cô đọng của sed là ưu điểm cho việc nhỏ, nhược điểm cho việc lớn.
Ba ý mang về
- sed mạnh hơn nhiều so với
s/a/b/: đo thật cờg(mọi lần),N(lần thứ N),I(bỏ hoa/thường); địa chỉ/mẫu/và khoảng dòng để nhắm chính xác dòng cần tác động;dxoá,-n ...pin chọn lọc như grep. - Nhóm bắt
\1 \2để sắp xếp lại dữ liệu: đo thật đảohost=localhost→localhost <- hostbằng-E "s/([a-z]+)=(.+)/\2 <- \1/"— sed làm được biến đổi cấu trúc, không chỉ thay chuỗi. - Bẫy
sed -iLinux vs macOS: GNU nhận-ikhông đối số, BSD đòi-i ""— viếtsed -i.bak "..."để chạy được cả hai; và luôn thử không-itrước vì sửa tại chỗ không undo được.
Nguồn
- GNU sed manual: https://www.gnu.org/software/sed/manual/sed.html
- man7.org — sed(1): https://man7.org/linux/man-pages/man1/sed.1.html
- grymoire — sed tutorial (kinh điển): https://www.grymoire.com/Unix/Sed.html
Phần sau ta sang công cụ xử lý dữ liệu theo cột mạnh nhất dòng lệnh: awk — vì sao nó vượt xa sed cho dữ liệu bảng, cách dùng biến, điều kiện, và tính tổng/nhóm ngay trên luồng.