Trong hệ điều hành Linux, Shell Scripting (phổ biến nhất là Bash) là "chất keo" kết dính các công cụ dòng lệnh lại với nhau. Cho dù bạn dùng Kubernetes, Docker, Terraform hay CI/CD (GitHub Actions, GitLab CI), hầu hết các tác vụ tự động hóa, container entrypoint (docker-entrypoint.sh) và kịch bản triển khai đều được viết bằng Bash.
Tuy nhiên, có một ranh giới rất lớn giữa:
- Kịch bản tay ngang: Chạy được lúc "trời yên biển lặng", nhưng khi có lỗi mạng hoặc biến bị rỗng thì âm thầm xóa nhầm dữ liệu, nuốt lỗi hoặc treo hệ thống.
- Kịch bản của Chuyên gia SRE: Bắt buộc có cơ chế phòng thủ (Defensive Programming), tự dừng khi gặp sự cố, luôn dọn dẹp tài nguyên rác trước khi thoát và log rõ ràng từng bước.
🎯 4 Ngôn Ngữ Kịch Bản Phổ Biến Nhất Trên Linux
| Ngôn ngữ | Vai trò chính | Khi nào nên dùng? | Khi nào KHÔNG nên dùng? |
|---|---|---|---|
| Bash / POSIX sh | Tự động hóa hệ thống, CI/CD, Container Entrypoint | Tác vụ dưới 200 dòng, gọi nhiều lệnh CLI của OS | Logic xử lý nghiệp vụ phức tạp, xử lý mảng đa chiều |
| Python | Tự động hóa nâng cao, tương tác Cloud SDK (boto3) | Cần gọi REST API phức tạp, phân tích dữ liệu, script > 200 dòng | Khi môi trường tối giản (Distroless / Alpine không có Python) |
| Awk / Sed | Xử lý văn bản, lọc và biến đổi luồng dữ liệu stream | Trích xuất cột, thay thế chuỗi regex siêu tốc ngay trên CLI | Không dùng để viết ứng dụng hoàn chỉnh |
| Go (Single-binary) | Công cụ CLI nội bộ, DevOps Tooling | Cần tốc độ cao, đa luồng, đóng gói 1 file nhị phân chạy ngay | Tác vụ chỉ cần gọi 2-3 lệnh Linux cơ bản |
1. Shebang (#!) & Trình Thông Dịch
Dòng đầu tiên của mọi file script bắt buộc phải là Shebang. Nó chỉ dẫn cho Kernel biết chương trình nào sẽ chịu trách nhiệm thông dịch file này:
#!/usr/bin/env bash
[!TIP] Tại sao nên dùng
#!/usr/bin/env bashthay vì#!/bin/bash? Trên một số hệ điều hành (như FreeBSD, macOS hoặc môi trường NixOS), Bash không nằm ở/bin/bashmà ở/usr/local/bin/bash. Dùng/usr/bin/env bashsẽ tự động tìm kiếm Bash theo biến môi trườngPATH, giúp script chạy đa nền tảng một cách trơn tru.
2. Quy Tắc Sống Còn: "Bash Strict Mode"
Nếu chỉ được chọn một điều duy nhất cần nhớ về Shell Scripting, hãy luôn đặt dòng này ngay sau dòng Shebang:
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
Tại sao bộ cờ này cứu bạn khỏi những thảm họa Production?
-e(errexit): Dừng script ngay lập tức khi bất kỳ lệnh nào trả về lỗi (exit code khác 0). Mặc định, Bash sẽ lờ đi lệnh lỗi và tiếp tục chạy các dòng sau!⚠️ Thảm họa nếu thiếu
-e:cd /tmp/backup_folder # Lệnh này bị lỗi do thư mục chưa tạo! rm -rf * # Vì lệnh trên fail, bạn vẫn đang ở /home hoặc / và XÓA SẠCH MỌI THỨ!-u(nounset): Báo lỗi và dừng script ngay lập tức nếu sử dụng một biến chưa từng được khai báo.⚠️ Thảm họa nếu thiếu
-u:rm -rf /tmp/$SUBDIR/* # Nếu $SUBDIR bị rỗng hoặc gõ sai chính tả, lệnh biến thành 'rm -rf /tmp//*'!-o pipefail: Mặc định, trong đường ốngcmd1 | cmd2 | cmd3, Bash chỉ quan tâm exit code của lệnh cuối cùng (cmd3). Nếucmd1chết nhưngcmd3chạy được, Bash vẫn xem là thành công! Bậtpipefailgiúp script fail nếu bất kỳ mắt xích nào trong pipeline gặp sự cố.IFS=$'\n\t': Đặt ký tự phân tách nội bộ chỉ gồm xuống dòng và tab, ngăn chặn lỗi tách từ khi duyệt file có tên chứa khoảng trắng.
3. Biến & Mở Rộng Biến An Toàn (Variables)
3.1. Luôn bọc biến trong dấu ngoặc kép: "$VAR"
# ❌ Nguy hiểm: Dễ bị lỗi Word Splitting nếu đường dẫn có khoảng trắng
FILE_PATH="/var/log/my app.log"
rm $FILE_PATH # Bash sẽ hiểu là xóa 2 file: '/var/log/my' và 'app.log'!
# ✅ Chuẩn chuyên gia: Luôn bọc ngoặc kép
rm "$FILE_PATH"
3.2. Giá trị mặc định cho biến (Default Values)
Rất hữu ích khi viết script Docker hoặc CI/CD để cho phép người dùng ghi đè tham số qua biến môi trường:
# Nếu biến APP_PORT chưa có, tự động gán giá trị 8080
PORT="${APP_PORT:-8080}"
# Nếu biến DB_HOST không có, dừng script và in thông báo lỗi
DB_HOST="${1:?Lỗi: Bạn chưa cung cấp DB_HOST làm tham số đầu tiên!}"
3.3. Các tham số đặc biệt (Special Parameters)
| Biến | Ý nghĩa | Ví dụ thực tế |
|---|---|---|
$0 | Tên của file script đang chạy | In menu hướng dẫn sử dụng |
$1, $2, ... | Các tham số truyền vào từ dòng lệnh | ./deploy.sh staging v1.2.0 |
$# | Tổng số lượng tham số truyền vào | if [[ $# -lt 2 ]]; then ... |
"$@" | Toàn bộ danh sách tham số (giữ nguyên từng phần tử độc lập) | Truyền tiếp tham số vào lệnh khác |
$? | Mã thoát (Exit code) của lệnh chạy gần nhất | 0 = Thành công, khác 0 = Thất bại |
$$ | PID của chính tiến trình script đang chạy | Tạo file tạm độc nhất /tmp/app_$$.log |
4. Cấu Trúc Điều Khiển Hiện Đại
4.1. Câu lệnh điều kiện: Luôn dùng [[ ... ]] thay vì [ ... ]
Trong Bash hiện đại, cú pháp ngoặc vuông đôi [[ ... ]] là chuẩn vàng:
- Không bị lỗi cú pháp nếu biến bên trong bị rỗng.
- Hỗ trợ so khớp mẫu chuỗi và Regex bằng toán tử
=~. - Dùng được toán tử logic
&&,||tự nhiên mà không cần cờ-a,-o.
ENV="production"
VERSION="v2.4.1"
# Kiểm tra logic kết hợp
if [[ "$ENV" == "production" && "$VERSION" =~ ^v[0-9]+\.[0-9]+ ]]; then
echo "Chuẩn bị deploy phiên bản hợp lệ lên Production..."
fi
# Kiểm tra sự tồn tại của file hoặc thư mục
if [[ -f "/etc/nginx/nginx.conf" ]]; then
echo "File cấu hình Nginx tồn tại."
fi
if [[ -d "/var/log" ]]; then
echo "Thư mục /var/log tồn tại."
fi
4.2. Vòng lặp đọc File chuẩn xác (Line-by-line)
Đừng dùng for line in $(cat file.txt) vì nó sẽ bị vỡ dòng nếu có dấu khoảng trắng! Hãy dùng vòng lặp while read:
# Cách đọc từng dòng file chuẩn nhất trong Bash:
while IFS= read -r line || [[ -n "$line" ]]; do
echo "Đang xử lý mục: $line"
done < "servers.txt"
5. Bẫy Lỗi & Tự Động Dọn Dẹp (trap)
Kịch bản chuyên nghiệp phải biết tự dọn dẹp "bãi rác" nó tạo ra (file tạm, lock file, port kết nối), kể cả khi script bị người dùng bấm Ctrl + C (SIGINT) hoặc đứt gánh giữa chừng.
Lệnh trap cho phép bạn đăng ký một hành động trước khi tiến trình thoát (EXIT):
#!/usr/bin/env bash
set -euo pipefail
# 1. Tạo file tạm thời an toàn
TMP_FILE=$(mktemp /tmp/deploy_payload.XXXXXX)
# 2. Đăng ký bẫy: Dù script thành công hay thất bại, EXIT luôn dọn dẹp file tạm
cleanup() {
echo "🧹 Đang dọn dẹp tài nguyên tạm thời..."
rm -f "$TMP_FILE"
}
trap cleanup EXIT
# 3. Thao tác bình thường
echo "Đang ghi dữ liệu vào $TMP_FILE..."
# Nếu có lỗi xảy ra ở đây, hàm cleanup() vẫn tự động được thực thi!
6. Mẫu Kịch Bản Chuẩn Production (Boilerplate)
Dưới đây là khung mẫu (Template) đạt chuẩn vận hành SRE để bạn dùng làm khung sườn cho mọi script tự động hóa:
#!/usr/bin/env bash
# ==============================================================================
# Script Name: deploy_service.sh
# Description: Tự động hóa kiểm tra và triển khai dịch vụ lên máy chủ
# ==============================================================================
set -euo pipefail
IFS=$'\n\t'
# Màu sắc hiển thị terminal
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m' # No Color
# Hàm ghi log có mốc thời gian chuẩn
log_info() { echo -e "[$(date +'%Y-%m-%dT%H:%M:%S%z')] ${GREEN}[INFO]${NC} $*"; }
log_warn() { echo -e "[$(date +'%Y-%m-%dT%H:%M:%S%z')] ${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "[$(date +'%Y-%m-%dT%H:%M:%S%z')] ${RED}[ERROR]${NC} $*" >&2; }
# Hiển thị hướng dẫn
usage() {
cat << EOF
Sử dụng: $(basename "$0") [-e ENVIRONMENT] [-v VERSION] [-h]
Tùy chọn:
-e Môi trường triển khai (staging | production)
-v Phiên bản dịch vụ (vd: v1.0.0)
-h Hiển thị trợ giúp
EOF
exit 1
}
# Khởi tạo biến mặc định
ENVIRONMENT=""
VERSION=""
# Phân tích tham số truyền vào bằng getopts
while getopts ":e:v:h" opt; do
case "$opt" in
e) ENVIRONMENT="$OPTARG" ;;
v) VERSION="$OPTARG" ;;
h) usage ;;
\?) log_error "Tùy chọn không hợp lệ: -$OPTARG"; usage ;;
:) log_error "Tùy chọn -$OPTARG bắt buộc phải có giá trị."; usage ;;
esac
done
# Kiểm tra tham số bắt buộc
if [[ -z "$ENVIRONMENT" || -z "$VERSION" ]]; then
log_error "Thiếu tham số bắt buộc (-e hoặc -v)."
usage
fi
main() {
log_info "Bắt đầu triển khai phiên bản [$VERSION] lên môi trường [$ENVIRONMENT]..."
# Thực hiện logic chính ở đây...
log_info "Triển khai hoàn tất thành công!"
}
main
7. Đảm Bảo Chất Lượng Với ShellCheck
Trong phát triển phần mềm hiện đại, không ai kiểm tra script bằng mắt thường. ShellCheck là công cụ phân tích tĩnh (Static Analysis) số 1 dành cho Shell Scripting:
# Cài đặt trên Ubuntu / Debian
sudo apt-get install -y shellcheck
# Quét kiểm tra script tìm lỗ hổng cú pháp và thói quen xấu
shellcheck deploy_service.sh
[!NOTE] Hãy tích hợp
shellcheckvào luồng Pre-commit hook hoặc CI/CD Pipeline để tự động chặn mọi script cẩu thả trước khi được merge vào kho mã nguồn.
⚡ Bảng Tra Cứu Quy Tắc Vàng (SRE Checklist)
| Quy tắc | Cần làm | Tránh làm |
|---|---|---|
| Shebang | #!/usr/bin/env bash | #!/bin/sh nhưng dùng cú pháp của Bash |
| Bảo vệ lỗi | Luôn có set -euo pipefail ở đầu file | Chạy script mặc định không bắt lỗi |
| Dùng biến | "$MY_VAR" (luôn bọc ngoặc kép) | $MY_VAR (dễ lỗi khi có khoảng trắng) |
| Phạm vi biến | Khai báo local var bên trong hàm | Để biến trong hàm tràn ra global scope |
| Kiểm tra điều kiện | Dùng [[ ... ]] | Dùng [ ... ] dễ lỗi cú pháp |
| Dọn dẹp rác | Dùng trap 'cleanup' EXIT | Để lại file tạm rác khi script bị crash |
| Kiểm tra cú pháp | Dùng shellcheck và bash -n | Deploy thẳng lên server rồi chạy thử |
Bài tiếp theo đề xuất: Quản Trị Process, Memory & Filesystem – Hiểu sâu vòng đời tiến trình, cơ chế cấp phát bộ nhớ RAM (buff/cache, OOM Killer) và xử lý sự cố Filesystem nâng cao.