Vòng lặp trong Bash cho DevOps
Ở bài trước chúng ta đã dùng điều kiện để script biết rẽ nhánh theo trạng thái hệ thống. Nhưng trong công việc DevOps, rất nhiều tác vụ không chỉ chạy một lần: kiểm tra nhiều server, đọc từng dòng log, retry một lệnh có thể lỗi tạm thời, hoặc xử lý hàng loạt file cấu hình.
Vòng lặp trong Bash giúp bạn lặp lại một khối lệnh theo danh sách, theo điều kiện, hoặc cho đến khi một điều kiện được thoả mãn. Bài này đi qua for, while, until, break, continue và các ví dụ thực hành gần với vận hành hằng ngày.
for in — lặp qua danh sách
Theo GNU Bash Manual, dạng for name in words; do ...; done sẽ mở rộng danh sách words, rồi chạy khối lệnh một lần cho từng phần tử. Ở mỗi lượt lặp, biến name nhận giá trị hiện tại.
Cú pháp phổ biến:
| |
Ví dụ — kiểm tra nhanh nhiều host bằng ping:
| |
Điểm quan trọng là dùng "${HOSTS[@]}" thay vì ${HOSTS[@]} trần. Cách quote này giữ nguyên từng phần tử array, kể cả khi giá trị có khoảng trắng.
for kiểu C — lặp theo bộ đếm
Bash cũng hỗ trợ dạng for (( expr1; expr2; expr3 )), tương tự ngôn ngữ C. Dạng này phù hợp khi bạn cần bộ đếm rõ ràng: chạy đúng N lần, đánh số retry, hoặc tạo tên file theo index.
| |
Ví dụ — tạo 3 file log giả lập cho môi trường test:
| |
Trong (( ... )), bạn có thể dùng toán tử số học quen thuộc như <=, ++, +=. Tên biến không bắt buộc có $ ở phía trước.
while — lặp khi điều kiện còn đúng
while chạy khối lệnh miễn là lệnh kiểm tra trả exit code 0. Đây là lựa chọn tốt khi số lần lặp chưa biết trước: đọc file đến hết, chờ service sẵn sàng, hoặc polling một endpoint.
Cú pháp:
| |
Ví dụ — đọc file log theo từng dòng và lọc dòng lỗi:
| |
IFS= read -r LINE là pattern nên dùng khi đọc từng dòng:
IFS=tránh việc Bash tự cắt khoảng trắng đầu/cuối dòng.read -rgiữ nguyên dấu\, không coi nó là ký tự escape.done < "${LOG_FILE}"đưa file vào stdin của vòng lặp, tránh cần gọicatkhông cần thiết.
until — lặp cho đến khi điều kiện đúng
until gần giống while, nhưng logic ngược lại: nó chạy khối lệnh miễn là lệnh kiểm tra trả non-zero, và dừng khi điều kiện trả 0.
Cú pháp:
| |
Ví dụ — chờ một endpoint healthcheck sẵn sàng:
| |
until đọc rất tự nhiên trong các tình huống “lặp cho tới khi thành công”. Nếu team của bạn thấy while ! command; do ... dễ hiểu hơn, dùng while cũng hoàn toàn ổn.
break và continue
break thoát khỏi vòng lặp hiện tại. continue bỏ qua phần còn lại của lượt lặp hiện tại và chuyển sang lượt tiếp theo. Theo GNU Bash Manual, cả hai đều dùng được trong for, while, until và select.
Ví dụ — bỏ qua file không phải .log, dừng khi gặp log quá lớn:
| |
Dòng [[ -e "${FILE}" ]] || continue xử lý trường hợp glob /var/log/*.log không match file nào. Nếu không có file, Bash có thể giữ nguyên pattern thành chuỗi literal, nên cần kiểm tra tồn tại trước khi xử lý.
Thực hành DevOps: lặp qua danh sách server SSH
Ví dụ này đọc danh sách server từ file, SSH vào từng host và chạy một lệnh kiểm tra ngắn. Tên server, user và command đều dùng placeholder chung, không phụ thuộc môi trường thật.
Tạo file servers.txt:
| |
Tạo script check_servers.sh:
| |
Chạy thử:
| |
Một vài điểm đáng chú ý:
BatchMode=yesgiúp SSH không hỏi password/passphrase trong automation. Nếu key chưa sẵn sàng, lệnh sẽ fail thay vì treo script.ConnectTimeout=5tránh chờ quá lâu khi một host không phản hồi.- Dòng rỗng và dòng comment bắt đầu bằng
#được bỏ qua bằngcontinue. - Không hardcode user nhạy cảm: script lấy
SSH_USERtừ biến môi trường, mặc định làdeploy.
Thực hành DevOps: retry lệnh thất bại
Trong vận hành, có những lỗi chỉ tạm thời: network chập chờn, registry chưa phản hồi, endpoint vừa restart xong. Vòng lặp giúp bạn retry có kiểm soát thay vì chạy lại thủ công.
| |
Ở đây, curl -f trả lỗi nếu HTTP status là 4xx/5xx, -sS giữ output gọn nhưng vẫn in lỗi khi thất bại. Exit code cuối cùng giúp pipeline biết nên tiếp tục hay dừng.
Sai sót thường gặp
- Lặp qua output của
ls:for FILE in $(ls)dễ vỡ khi tên file có khoảng trắng hoặc ký tự đặc biệt. Hãy dùng glob (for FILE in *.log) hoặcfind ... -print0cho case phức tạp. - Quên quote biến: Luôn dùng
"${VAR}", đặc biệt khi biến là đường dẫn, hostname hoặc dữ liệu đọc từ file. - Dùng pipe làm mất biến ngoài vòng lặp:
cat file | while read ...thường chạy vòng lặp trong subshell, thay đổi biến bên trong có thể không còn sau vòng lặp. Ưu tiênwhile ...; done < file. - Vòng lặp vô hạn không có điều kiện dừng: Khi dùng
while true, luôn cóbreak, timeout, hoặc giới hạn số lần thử. - Không xử lý dòng rỗng/comment: Khi đọc danh sách server hoặc config, nên bỏ qua dòng rỗng và comment để script bền hơn.
Ghi chú triển khai
- Khi áp dụng vào dự án của bạn, hãy xác định rõ vòng lặp đang lặp theo danh sách hay theo trạng thái:
- Có danh sách sẵn → thường dùng
for. - Đọc từng dòng hoặc chờ điều kiện còn đúng → thường dùng
while. - Chờ cho đến khi lệnh thành công → cân nhắc
until.
- Có danh sách sẵn → thường dùng
- Best practices:
- Dùng
IFS= read -rkhi đọc file theo dòng. - Quote array bằng
"${ARRAY[@]}"khi lặp qua danh sách. - Với retry, luôn có
MAX_RETRIESvàSLEEP_SECONDSrõ ràng. - Với SSH automation, thêm timeout và tránh prompt tương tác.
- Dùng
- Troubleshooting:
- Vòng lặp không chạy? → Kiểm tra danh sách đầu vào có rỗng không, glob có match file không.
- Script dừng giữa chừng khi dùng
set -e? → Một lệnh trong vòng lặp trả non-zero nhưng chưa được bọc bằngif,||, hoặc xử lý exit code. - Đọc file bị mất khoảng trắng? → Đảm bảo dùng
IFS= read -r LINE.
🎯 Lời kết
Vòng lặp là nền tảng để Bash chuyển từ các script chạy một lần sang automation thật sự: xử lý nhiều server, nhiều file, nhiều dòng log và nhiều lần retry. Khi kết hợp for, while, until với điều kiện ở bài trước, bạn đã có thể viết các script DevOps nhỏ nhưng rất hữu dụng cho kiểm tra, triển khai và vận hành hằng ngày.
Ở bài tiếp theo, chúng ta sẽ đi vào xử lý file trong Bash: đọc, ghi, redirect output, dùng tee, find, xargs và các pattern quản lý log/config an toàn hơn. 🚀
Tài liệu tham khảo
- GNU Bash Manual — Looping Constructs — Tài liệu chính thức về
for,while,until. - GNU Bash Manual — Bourne Shell Builtins — Tài liệu chính thức về
breakvàcontinue. - GNU Bash Manual — Bash Builtin Commands — Tài liệu chính thức về
read,mapfilevà các builtin khác. - ShellCheck Wiki — SC2045 — Vì sao không nên lặp qua output của
ls.
