Xử lý file trong Bash cho DevOps
Ở bài trước chúng ta đã dùng vòng lặp để xử lý nhiều server, nhiều dòng log và retry các lệnh có thể lỗi tạm thời. Bước tiếp theo rất tự nhiên là xử lý file: đọc log, ghi report, append output, tạo file cấu hình, tìm file cũ và truyền danh sách file cho lệnh khác.
Trong DevOps, phần lớn automation nhỏ đều chạm tới file: log của service, file .env, config Nginx, manifest YAML, danh sách host, artifact build hoặc backup. Bài này tập trung vào các pattern Bash thực dụng: cat, head, tail, redirect, here-doc, tee, đọc từng dòng, kiểm tra file, find, xargs và hai ví dụ thực hành.
Đọc nhanh nội dung file với cat, tac, head, tail
cat đọc một hoặc nhiều file rồi ghi ra standard output. Theo GNU Coreutils, nếu không truyền file, cat đọc từ standard input.
| |
Một vài lệnh hay dùng khi xem log hoặc config:
| |
tail -f theo dõi file descriptor hiện tại. Khi log bị rotate, file cũ có thể bị rename và app mở file mới. GNU tail -F tương đương --follow=name --retry, thường tiện hơn cho log vận hành vì nó cố mở lại file theo tên.
Redirect output: ghi mới, append và tách stdout/stderr
Bash xử lý redirect từ trái sang phải. Một số dạng phổ biến:
| |
Ví dụ ghi log cho một bước deploy:
| |
Dùng block { ...; } >> "${LOG_FILE}" 2>&1 giúp gom log của nhiều lệnh vào cùng một file mà không phải lặp redirect ở từng dòng.
Lưu ý: > sẽ ghi đè file. Nếu muốn giảm rủi ro overwrite nhầm trong shell hiện tại, có thể bật set -o noclobber; khi cần ghi đè có chủ đích, dùng >| file.
Here-doc: tạo file cấu hình từ script
Here-doc (<<EOF) đưa nhiều dòng text vào stdin của một lệnh. Nó rất hữu ích khi cần tạo config mẫu, unit file, hoặc payload JSON nhỏ.
| |
Nếu delimiter không được quote, Bash sẽ expand biến bên trong here-doc:
| |
Nếu muốn giữ nguyên $, backtick hoặc ${VAR} trong file output, quote delimiter:
| |
Theo Bash Manual, khi dùng <<-EOF, Bash sẽ bỏ các tab ở đầu dòng trong here-doc. Cách này giúp script dễ đọc hơn, nhưng chỉ strip tab, không strip space.
tee: vừa hiển thị vừa lưu file
Redirect > sẽ đưa output vào file và thường không còn hiển thị trên terminal. tee copy standard input ra standard output và đồng thời ghi vào file.
| |
Theo GNU Coreutils, tee sẽ overwrite file nếu không dùng -a; tee -a append vào file.
Ví dụ vừa xem log build vừa lưu lại artifact log:
| |
Ở đây 2>&1 đặt trước pipe để stderr cũng đi qua tee. Nếu chỉ viết ./build.sh | tee ..., nhiều lỗi trên stderr vẫn hiện ra terminal nhưng không được lưu vào file log.
Đọc file theo từng dòng
Pattern an toàn khi đọc file line-by-line là while IFS= read -r LINE; do ...; done < file.
| |
Giải thích nhanh:
IFS=giữ nguyên khoảng trắng đầu/cuối dòng.read -rkhông coi\là escape character.done < "${SERVER_FILE}"tránh patterncat file | while ..., vốn có thể làm vòng lặp chạy trong subshell ở một số shell và làm mất biến sau vòng lặp.- Quote
"${SERVER_FILE}"để đường dẫn có khoảng trắng vẫn hoạt động.
Kiểm tra file, thư mục và quyền trước khi thao tác
Trước khi đọc/ghi/xóa file trong automation, hãy kiểm tra điều kiện rõ ràng. Một số test hay dùng trong [[ ... ]]:
| |
Ví dụ backup config chỉ khi file tồn tại và đọc được:
| |
Dấu -- sau cp giúp kết thúc danh sách option. Đây là thói quen tốt khi biến có thể bắt đầu bằng -.
find: tìm file theo điều kiện
find phù hợp khi cần tìm file theo tên, loại, thời gian, kích thước hoặc thư mục con.
| |
Một số điều kiện thường gặp:
-type f: chỉ file thường.-type d: chỉ thư mục.-name "*.log": match theo tên.-mtime +7: file có modification time hơn 7 ngày.-size +100M: file lớn hơn 100 MiB theo cú pháp GNU find.-maxdepth 1: không đi quá sâu khỏi thư mục hiện tại.
Ví dụ xem log cũ hơn 14 ngày nhưng chưa xóa:
| |
Khi viết script cleanup, nên chạy -print trước để review danh sách, sau đó mới đổi sang hành động xóa hoặc archive.
xargs: truyền danh sách file cho lệnh khác
xargs đọc dữ liệu từ stdin, gom thành argument và chạy command. Nó hữu ích khi danh sách file dài hoặc cần truyền kết quả của find cho lệnh khác.
Không nên dùng dạng mặc định cho file name tùy ý:
| |
Mặc định xargs tách input theo whitespace, nên tên file có space, tab hoặc newline có thể bị hiểu sai. GNU findutils khuyến nghị dùng find -print0 kết hợp xargs -0 để phân tách bằng NUL character:
| |
Nếu dùng GNU xargs, thêm -r để không chạy command khi input rỗng:
| |
Một lựa chọn khác là dùng find -exec ... {} +, portable và tránh pipe:
| |
Thực hành DevOps: rotate log thủ công
Trong production, log rotation thường nên giao cho logrotate hoặc logging stack. Nhưng hiểu một script rotate nhỏ giúp bạn nắm rõ các thao tác file: kiểm tra size, rename, tạo file mới, compress và cleanup.
| |
Một vài lưu ý:
: > "${LOG_FILE}"tạo file rỗng mới bằng shell builtin:và redirect output rỗng.- Script này phù hợp để học hoặc dùng cho service nhỏ. Với app đang ghi log liên tục, rotate thủ công có thể cần signal/reopen log tùy ứng dụng.
- Dùng
find ... -print -deleteđể vừa thấy file nào bị xóa vừa cleanup.
Thực hành DevOps: backup config trước khi deploy
Trước khi deploy, một bước an toàn là backup các file config quan trọng vào thư mục riêng theo timestamp.
| |
cp -p giữ lại mode, ownership và timestamp nếu quyền hệ thống cho phép. TARGET="${BACKUP_DIR}${CONFIG_FILE}" giữ nguyên cấu trúc đường dẫn gốc bên trong thư mục backup, giúp restore dễ hơn.
Sai sót thường gặp
- Dùng
>khi muốn append:>overwrite file; dùng>>hoặctee -anếu muốn ghi nối tiếp. - Đặt sai thứ tự redirect:
command 2>&1 >filekháccommand >file 2>&1. Bash xử lý redirect từ trái sang phải. - Quên quote đường dẫn: Luôn dùng
"${FILE}", đặc biệt với path đọc từ input. - Dùng
xargsmặc định với file name tùy ý: Ưu tiênfind -print0 | xargs -0hoặcfind -exec ... {} +. - Xóa file ngay khi chưa review: Với cleanup, chạy
find ... -printtrước, sau đó mới thêm-deletehoặcrm. - Tạo here-doc bị expand ngoài ý muốn: Quote delimiter (
<<'EOF') nếu muốn giữ nguyên${VAR}trong file output.
Ghi chú triển khai
- Khi áp dụng vào dự án của bạn, hãy phân biệt rõ thao tác:
- Xem nhanh file/log →
cat,head,tail,tail -F. - Ghi log script → redirect block hoặc
tee -a. - Tạo config nhiều dòng → here-doc, quote delimiter nếu cần template literal.
- Tìm/xử lý nhiều file →
find,find -exec ... {} +, hoặcfind -print0 | xargs -0.
- Xem nhanh file/log →
- Best practices:
- Bắt đầu script bằng
set -euo pipefailkhi phù hợp. - Kiểm tra
-r,-w,-f,-dtrước khi thao tác nguy hiểm. - Dùng
--trước biến path trong các lệnh nhưcp,mv,rm,gzip. - Với cleanup, log lại file bị tác động bằng
-printhoặcecho.
- Bắt đầu script bằng
- Troubleshooting:
- File log không ghi đủ stderr? → Đảm bảo có
2>&1trước pipe hoặc redirect đúng thứ tự. tail -fkhông thấy log mới sau rotate? → Thửtail -F.- Script lỗi với tên file có space? → Kiểm tra quote biến và cách dùng
xargs.
- File log không ghi đủ stderr? → Đảm bảo có
🎯 Lời kết
Xử lý file là kỹ năng cốt lõi khi viết Bash cho DevOps. Khi nắm chắc redirect, here-doc, tee, đọc từng dòng, kiểm tra quyền, find và xargs, bạn có thể viết các script nhỏ nhưng an toàn hơn cho log, config, backup và cleanup.
Ở bài tiếp theo, chúng ta sẽ đi vào text processing với grep, awk và sed: lọc log, trích cột, thay đổi config và đếm dữ liệu từ file text hiệu quả hơn. 🚀
Tài liệu tham khảo
- GNU Bash Manual — Redirections — Tài liệu chính thức về redirect, file descriptor và here-doc.
- GNU Coreutils Manual — cat — Cách
catđọc và ghi file/stdin/stdout. - GNU Coreutils Manual — head — Tài liệu chính thức về
head -n,head -c. - GNU Coreutils Manual — tail — Tài liệu chính thức về
tail -f,tail -F,--follow=name. - GNU Coreutils Manual — tee — Tài liệu chính thức về
teevàtee -a. - GNU Findutils Manual — Tài liệu chính thức về
find,xargs,-print0vàxargs -0.
