Bash phù hợp để điều phối các chương trình và thao tác file; nó không nên thay Python cho logic dữ liệu phức tạp. Một script tốt ưu tiên khả năng dự đoán, kiểm thử và quan sát.
Bài viết xây script ingest_sales.sh từ đầu, có tham số, validation, trap, lock, logging, idempotency và exit code rõ.
Mục lục
Sản phẩm người đọc sẽ hoàn thành
Sau bài viết, người học hoàn thành script Bash production-ready để ingest CSV theo ngày cùng test cases và runbook. Project được tổ chức thành các thư mục src, config, logs, tests và evidence. README ghi rõ phiên bản Ubuntu, kiến trúc máy, user thực thi, cách chạy, cách kiểm thử và cách khôi phục.





Bộ dữ liệu hoặc workload thực hành là file sales_YYYY-MM-DD.csv được kiểm tra header, đếm dòng, chuyển vào processed và archive. Trước khi bắt đầu, tạo snapshot hoặc bản sao dữ liệu, xác nhận còn đủ dung lượng và mở một terminal thứ hai để cứu hộ nếu phiên làm việc chính gặp lỗi. Những nguyên tắc này giúp bài tập gần với cách vận hành Linux trong doanh nghiệp.
Môi trường và quy ước an toàn
mkdir -p ~/linux-lab/{src,config,logs,tests,evidence}
cd ~/linux-lab
printf "started_at=%s\n" "$(date -Is)" | tee evidence/session.txt
uname -a | tee -a evidence/session.txt
cat /etc/os-release | tee -a evidence/session.txt
Bài thực hành dùng Ubuntu Server LTS trên máy ảo tối thiểu 2 vCPU, 4 GB RAM và 20 GB ổ đĩa. Không chạy trực tiếp trên máy production. Những lệnh có khả năng xóa dữ liệu, sửa quyền hoặc khởi động lại service phải được thử trên thư mục lab trước, đồng thời ghi lại trạng thái trước và sau.
1. Shebang và strict mode
Interpreter và chính sách lỗi phải rõ từ dòng đầu. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Tạo script với Bash, strict mode và IFS an toàn. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/1. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
cat > src/ingest_sales.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
EOF
chmod +x src/ingest_sales.sh
Kết quả cần thấy. File executable và Bash kiểm tra cú pháp không lỗi. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Pin yêu cầu Bash version nếu dùng tính năng mới. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
2. Biến và quoting
Word splitting và glob expansion làm tên file có khoảng trắng bị vỡ. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Khai báo readonly, luôn quote expansion và dùng array. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/2. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
readonly BASE_DIR="$HOME/linux-lab"
files=("$BASE_DIR"/data/raw/*.csv)
printf "%s\n" "${files[@]}"
Kết quả cần thấy. Mỗi đường dẫn là một phần tử và không bị tách theo khoảng trắng. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Không lưu secret trong biến được in bởi set -x. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
3. Tham số và usage
Script thiếu interface rõ gây gọi sai ở scheduler. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Parse date và input directory, trả code 64 khi dùng sai. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/3. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
usage(){ echo "Usage: $0 --date YYYY-MM-DD" >&2; exit 64; }
[[ ${1:-} == "--date" && -n ${2:-} ]] || usage
run_date=$2
Kết quả cần thấy. Thiếu tham số hiển thị usage và trả mã khác 0. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. CLI contract được version và backward compatible khi có consumer. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
4. Validation đầu vào
File tồn tại không có nghĩa đúng schema hoặc không rỗng. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Kiểm tra regular file, size, header và định dạng ngày. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/4. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
input="data/raw/sales_${run_date}.csv"
[[ -s "$input" ]] || { echo "missing input" >&2; exit 66; }
head -1 "$input" | grep -qx "id,date,revenue"
Kết quả cần thấy. File sai header bị chặn trước khi tạo output. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Validation nhiều lớp và quarantine thay vì sửa file nguồn. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
5. Function nhỏ
Function giúp tách logging, validation và processing. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Viết log function có timestamp UTC và level. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/5. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
log(){ printf "%s level=%s msg=%q\n" "$(date -u +%FT%TZ)" "$1" "$2"; }
log INFO "starting ingest"
Kết quả cần thấy. Log một dòng, có timestamp và parse được. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Schema log ổn định để shipper thu thập và tạo alert. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
6. Temporary file và trap
Lỗi giữa chừng có thể để output dở dang. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Tạo mktemp, đăng ký cleanup trap và rename khi thành công. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/6. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
tmp=$(mktemp "data/staging/out.XXXXXX")
cleanup(){ rm -f "$tmp"; }
trap cleanup EXIT INT TERM
cp "$input" "$tmp"
Kết quả cần thấy. Temp file có tên ngẫu nhiên và được dọn khi thoát. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Temp nằm cùng filesystem với output để rename nguyên tử. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
7. Idempotency
Scheduler retry không được tạo duplicate. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Dùng marker hoặc checksum để nhận biết batch đã xử lý. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/7. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
sha=$(sha256sum "$input" | awk "{print \$1}")
marker="evidence/${run_date}.${sha}.done"
[[ ! -e "$marker" ]] || exit 0
Kết quả cần thấy. Cùng file chạy lại thoát an toàn mà không ghi output lần hai. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Idempotency key lưu trong database khi có nhiều worker. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
8. Lock chống chạy đồng thời
Hai instance có thể ghi cùng output. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Dùng flock trên file descriptor và trả lỗi rõ. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/8. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
exec 9>"/tmp/ingest-sales.lock"
flock -n 9 || { echo "already running" >&2; exit 75; }
Kết quả cần thấy. Instance thứ hai bị chặn và instance đầu giữ lock đến khi thoát. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Lock phân tán cần database hoặc coordinator, flock chỉ bảo vệ một host. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
9. Exit code và error handling
Mọi lỗi trả 1 làm monitoring thiếu ngữ cảnh. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Quy ước code cho usage, missing input, temporary failure và data error. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/9. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
if ! awk -F, "NR>1 && NF!=3{exit 1}" "$input"; then
log ERROR "invalid column count"
exit 65
fi
Kết quả cần thấy. Dữ liệu sai trả code 65 và log ERROR. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. Scheduler phân biệt lỗi retry được với lỗi dữ liệu cần can thiệp. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
10. ShellCheck và test
Review bằng mắt thường dễ bỏ lỗi quoting. Trong bối cảnh pipeline hằng ngày cần nhận CSV, kiểm tra chất lượng, archive và ghi log, bước này không chỉ nhằm ghi nhớ câu lệnh mà còn giúp hiểu trạng thái của hệ thống trước khi thay đổi. Mọi thao tác đều cần có đầu vào, kết quả mong đợi và cách quay lại trạng thái an toàn nếu xảy ra lỗi.
Thực hành. Chạy bash -n, ShellCheck và test success/failure. Chạy lệnh bằng tài khoản không có quyền root, quan sát mã thoát với echo $?, rồi lưu kết quả vào thư mục evidence/10. Không sao chép lệnh có sudo trước khi hiểu chính xác file, service hoặc quyền sẽ bị thay đổi.
bash -n src/ingest_sales.sh
shellcheck src/ingest_sales.sh
tests/run.sh
Kết quả cần thấy. Syntax, static analysis và test đều pass. Nếu đầu ra khác dự kiến, cần đọc thông báo lỗi từ trái sang phải, xác nhận đường dẫn tuyệt đối, quyền truy cập, biến môi trường và trạng thái tiến trình. Đây là thói quen quan trọng khi làm việc với server thật, nơi một lệnh chạy thành công chưa chắc tạo ra kết quả nghiệp vụ đúng.
Góc nhìn production. CI bắt buộc các gate trước khi merge và lưu artifact test. Với Bash scripting, tiêu chí hoàn thành gồm khả năng chạy lại, log đủ để điều tra, quyền tối thiểu, cấu hình có phiên bản và bằng chứng kiểm thử. Một thao tác thủ công chỉ được chấp nhận khi có lý do, người phê duyệt và kế hoạch tự động hóa sau đó.
Kiểm thử cuối bài
Kiểm thử gồm bốn lớp. Lớp chức năng xác nhận file hợp lệ xử lý một lần, file sai bị từ chối, chạy lại không nhân bản và concurrent run bị chặn. Lớp dữ liệu đối chiếu số file, kích thước, checksum hoặc số bản ghi trước và sau. Lớp vận hành kiểm tra retry, log, thời gian chạy và mức sử dụng tài nguyên. Lớp bảo mật xác nhận service không chạy bằng root nếu không cần thiết và file nhạy cảm không mở quyền cho group hoặc other.
set -euo pipefail
test -d ~/linux-lab/logs
test -s ~/linux-lab/evidence/session.txt
find ~/linux-lab -type f -perm -0002 -print | tee evidence/world_writable.txt
df -h | tee evidence/disk_after.txt
free -h | tee evidence/memory_after.txt
Một bài lab chỉ đạt khi lệnh có thể chạy lại mà không tạo trạng thái hỏng, lỗi trả mã thoát khác 0, log có timestamp và người khác làm theo README có thể tái tạo kết quả. Nếu kiểm thử chỉ dựa trên việc “màn hình không báo lỗi”, sản phẩm chưa đủ tiêu chuẩn production.
Những lỗi thường gặp và cách xử lý
Lỗi gồm không quote biến, dùng [ với chuỗi rỗng sai, bỏ set -euo pipefail, parse output không ổn định, không cleanup temp file và trả exit code 0 khi nghiệp vụ thất bại. Cách xử lý có hệ thống là tái hiện lỗi bằng đầu vào nhỏ, thu thập trạng thái bằng lệnh chỉ đọc, xác định lớp gây lỗi rồi mới thay đổi. Không sửa nhiều cấu hình cùng lúc vì sẽ mất khả năng xác định thay đổi nào thực sự giải quyết vấn đề.
Khi cần trợ giúp, cung cấp phiên bản hệ điều hành, câu lệnh đầy đủ đã che dữ liệu nhạy cảm, output, mã thoát, quyền của file liên quan và log trong đúng khoảng thời gian xảy ra lỗi. Mô tả tốt giúp rút ngắn thời gian điều tra và tránh các lời khuyên nguy hiểm như mở quyền 777 hoặc tắt firewall.
Đưa kỹ năng vào môi trường production
Script cần ShellCheck, shfmt, unit test, lock, structured log, timeout và metric. Secret không nằm trong argument hoặc log; version script được đóng gói và rollback được.
Trước mỗi thay đổi, cần có ticket, phạm vi ảnh hưởng, cửa sổ triển khai, backup, tiêu chí thành công, tiêu chí rollback và người chịu trách nhiệm. Sau thay đổi, lưu evidence, cập nhật runbook và theo dõi ít nhất một chu kỳ workload. Linux ổn định không đến từ một câu lệnh thần kỳ mà từ quy trình có thể kiểm chứng.
Bài tập mở rộng
- Viết một script chỉ đọc để thu thập trạng thái liên quan đến chủ đề và xuất báo cáo có timestamp.
- Tạo một lỗi có kiểm soát trong máy ảo, ghi triệu chứng, giả thuyết, bằng chứng và cách khôi phục.
- Chuyển ba thao tác thủ công thành script có
set -euo pipefailvà kiểm tra đầu vào. - Viết runbook một trang để người khác thực hiện mà không cần hỏi lại tác giả.
- Đánh giá thay đổi cần thiết nếu workload tăng gấp 100 lần.
Tài liệu tham khảo
- Ubuntu Server Documentation.
- GNU Coreutils và Bash Reference Manual.
- Linux man-pages project.
- systemd và OpenSSH documentation, sử dụng theo nội dung từng bài.
Kết luận
Bash có giá trị lớn nhất ở lớp keo nối các công cụ. Khi phạm vi được giữ rõ và error handling đầy đủ, script nhỏ có thể vận hành đáng tin cậy.
TechData.AI - Leading the Future.
Tham khảo các khoá học theo link: https://techdata.ai/techdata-ai-course/
Hoàng Minh.
