Function trong Bash cho DevOps
Ở bài trước chúng ta đã dùng grep, awk và sed để xử lý log/config. Khi script bắt đầu dài hơn, bạn sẽ gặp một vấn đề mới: nhiều đoạn code bị lặp lại — kiểm tra file, ghi log, validate biến môi trường, retry command, tạo backup trước khi sửa config.
Function giúp gom một nhóm lệnh thành một khối có tên, có thể gọi lại nhiều lần. Với DevOps, đây là bước quan trọng để biến các script “chạy được” thành script dễ đọc, dễ test và dễ bảo trì hơn.
Khai báo function trong Bash
Bash hỗ trợ hai kiểu khai báo phổ biến:
| |
Trong thực tế, kiểu name() { ...; } thường được dùng nhiều vì ngắn gọn và portable hơn giữa các shell kiểu POSIX. Với bài này, chúng ta tập trung vào Bash nên cả hai đều chạy được.
Gọi function giống gọi command:
| |
Lưu ý khoảng trắng và dấu ; khi viết một dòng:
| |
Nếu viết nhiều dòng, dấu ; trước } không cần thiết vì newline đã kết thúc command.
Function nhận tham số bằng $1, $@, $#
Trong function, Bash dùng các positional parameters giống script:
$1,$2, …: tham số thứ nhất, thứ hai, …$@: toàn bộ tham số, giữ từng argument riêng khi được quote thành"$@".$#: số lượng tham số.$0: tên script, không phải tên function.
Ví dụ function kiểm tra service:
| |
Khi cần truyền toàn bộ argument sang command khác, dùng "$@":
| |
"$@" giữ nguyên ranh giới argument. Đây là lựa chọn an toàn hơn so với $* khi tham số có khoảng trắng.
Validate tham số đầu vào
Function nên kiểm tra tham số bắt buộc ngay từ đầu để lỗi rõ ràng hơn.
| |
Dùng ${1:-} giúp tránh lỗi “unbound variable” khi script bật set -u mà function được gọi thiếu tham số.
Return value trong Bash là exit code
Function Bash không return dữ liệu dạng string như nhiều ngôn ngữ lập trình. return trong Bash trả về exit code từ 0 đến 255:
0: thành công.- Khác
0: lỗi hoặc trạng thái đặc biệt.
| |
Ở ví dụ trên, function không cần viết return rõ ràng. Exit code của lệnh cuối cùng ([[ ... ]]) sẽ trở thành exit code của function.
Nếu muốn function “trả về dữ liệu”, hãy in ra stdout rồi dùng command substitution:
| |
Nguyên tắc thực dụng: dùng exit code cho đúng/sai, dùng stdout cho dữ liệu.
Biến local để tránh side effect
Theo mặc định, biến trong function Bash là global trong phạm vi shell hiện tại. Dùng local để giới hạn biến trong function.
| |
Không dùng local, các biến như timestamp hoặc base_name có thể vô tình ghi đè biến cùng tên ở nơi khác trong script. Đây là lỗi khó debug khi script lớn dần.
Một thói quen tốt là khai báo local gần nơi dùng và quote biến khi truyền vào command:
| |
Tách function vào file khác với source
Khi nhiều script cùng cần logging, validation hoặc retry, bạn có thể tách function vào file thư viện nhỏ.
Ví dụ cấu trúc:
| |
File scripts/lib/log.sh:
| |
File scripts/deploy.sh:
| |
source chạy nội dung file trong shell hiện tại, nên các function trong log.sh sẽ có sẵn cho deploy.sh. Trong Bash, ${BASH_SOURCE[0]} giúp xác định đường dẫn file script hiện tại tốt hơn $0 khi file được source hoặc gọi từ thư mục khác.
Thực hành DevOps: thư viện logging nhỏ
Một thư viện logging tối thiểu nên có timestamp, level và tách stdout/stderr hợp lý.
| |
Đặt function nội bộ tên _log là convention đơn giản để báo hiệu “không gọi trực tiếp từ bên ngoài”. Bash không có private function thật sự, nên đây chỉ là quy ước.
Dùng trong script healthcheck:
| |
Ở đây curl --fail giúp HTTP 4xx/5xx được xem là lỗi, --silent --show-error giảm noise nhưng vẫn in lỗi cần thiết, và --max-time tránh script treo quá lâu.
Thực hành DevOps: retry command bằng function
Retry là pattern rất thường gặp khi gọi API, pull image, kiểm tra service vừa restart hoặc chạy lệnh có thể lỗi tạm thời.
| |
Điểm quan trọng:
shift 2bỏ hai tham số cấu hình để phần còn lại là command cần chạy."$@"chạy command với argument được giữ nguyên.- Function trả
0ngay khi command thành công, trả1sau khi hết số lần thử.
Bạn có thể kết hợp với logging library:
| |
Thực hành DevOps: deploy script có function rõ ràng
Ví dụ script deploy nhỏ, tách từng bước thành function để dễ đọc hơn:
| |
Pattern main "$@" giúp script có entrypoint rõ ràng. Các function phía trên định nghĩa hành vi, còn main mô tả luồng chạy chính.
Sai sót thường gặp
- Quên
local: Biến trong function có thể ghi đè biến global ngoài ý muốn. - Dùng
return "text":returnchỉ dành cho exit code số; muốn trả text thìecho/printfra stdout. - Không quote
"$@": Command wrapper dễ hỏng khi argument có khoảng trắng. - Gọi function trước khi khai báo: Bash đọc và chạy từ trên xuống; function phải được định nghĩa trước khi gọi.
- Dùng
$1trực tiếp khi bậtset -u: Nếu thiếu tham số, script lỗi ngay. Dùng${1:-}rồi validate. - Ghi log lỗi ra stdout: Error/warn nên đi stderr (
>&2) để stdout còn dùng cho dữ liệu/pipeline.
Ghi chú triển khai
- Khi áp dụng vào dự án của bạn, hãy bắt đầu bằng các function nhỏ cho phần lặp lại nhiều nhất:
log_info,log_warn,log_error.require_file,require_dir,require_env.retrycho lệnh có lỗi tạm thời.backup_filetrước khi sửa config.
- Best practices:
- Dùng
localcho biến trong function. - Dùng
returncho trạng thái thành công/thất bại, stdout cho dữ liệu. - Dùng
"$@"khi wrapper function gọi command khác. - Tách thư viện chung vào
scripts/lib/*.shvà load bằngsourcevới đường dẫn dựa trên${BASH_SOURCE[0]}. - Giữ function làm một việc rõ ràng; nếu function quá dài, tách tiếp.
- Dùng
- Troubleshooting:
- Function trả sai trạng thái? → In thử
$?ngay sau khi gọi hoặc chạybash -x script.sh. - Biến bị đổi bất ngờ? → Kiểm tra function thiếu
local. sourcekhông tìm thấy file? → Kiểm traSCRIPT_DIRvà chạy script từ thư mục khác để test.
- Function trả sai trạng thái? → In thử
🎯 Lời kết
Function là bước nâng cấp tự nhiên khi bạn viết Bash cho DevOps nhiều hơn một vài dòng. Chúng giúp tái sử dụng logic, gom logging/validation/retry vào nơi chung, giảm copy-paste và làm luồng deploy/healthcheck rõ ràng hơn.
Ở bài tiếp theo, chúng ta sẽ đi vào quản lý biến và môi trường trong Bash: biến local vs export, .env, getopts, $IFS và các biến đặc biệt như $?, $$, $!. 🚀
Tài liệu tham khảo
- GNU Bash Manual — Shell Functions — Tài liệu chính thức về function, positional parameters và exit status.
- GNU Bash Manual — Bourne Shell Builtins — Tham khảo
return,shiftvà các builtin liên quan. - GNU Bash Manual — Bash Variables — Tham khảo
${BASH_SOURCE[@]}và các biến Bash đặc biệt. - curl Documentation — Tham khảo
--fail,--silent,--show-error,--max-timedùng trong ví dụ healthcheck.
