Chương 10 — Automation & cron

Chương cuối — nơi mọi thứ bạn học được biến thành tự động. Không còn ngồi gõ lại cùng một lệnh mỗi sáng. Máy tính sẽ tự backup, tự dọn rác, tự kiểm tra ổ cứng — bạn chỉ cần mở Terminal để xem báo cáo. Đi nốt 10 section này và bạn đã đi trọn 10 chương CLI Mastery.

1. Tự động hoá là gì

Tự động hoá CLI có một công thức đơn giản: "việc lặp đi lặp lại → script → schedule". Mỗi khi bạn nhận ra mình gõ cùng một chuỗi lệnh nhiều hơn 2 lần, đó là tín hiệu nên đóng gói nó thành script; và nếu việc đó cần chạy theo lịch, ta giao cho một scheduler như cron / launchd / systemd lo phần đúng giờ.

Ba ví dụ kinh điển

# Pipeline tự động hoá điển hình
việc lặp lại  →  viết script .sh  →  chmod +x  →  test thủ công  →  schedule (cron/launchd)  →  log + alert
📘 Triết lý "set and forget"
Một script tự động tốt phải im lặng khi thành côngla to khi thất bại. Nếu mỗi lần chạy đều spam mail/notification, bạn sẽ học cách phớt lờ chúng — đến khi có lỗi thật cũng bỏ qua nốt.

2. cron — scheduler kinh điển

cron là daemon chạy nền trên Unix từ thập niên 70. Mỗi user có một crontab riêng — danh sách các job theo lịch. Sửa nó bằng crontab -e, xem nó bằng crontab -l, xoá sạch bằng crontab -r.

$ crontab -e          # mở editor để sửa job
$ crontab -l          # list các job hiện có
$ crontab -r          # xoá toàn bộ — cẩn thận!

Format 5 cột

 *  *  *  *  *   command-to-run
 │  │  │  │  │
 │  │  │  │  └── day of week (0-6, 0 = Chủ nhật)
 │  │  │  └───── month (1-12)
 │  │  └──────── day of month (1-31)
 │  └─────────── hour (0-23)
 └────────────── minute (0-59)

Pattern phổ biến

Cron expressionÝ nghĩa
* * * * *Mỗi phút
*/5 * * * *Mỗi 5 phút
0 * * * *Đầu mỗi giờ (xx:00)
0 2 * * *Mỗi đêm 2h sáng
0 9 * * 1Mỗi thứ Hai 9h sáng
30 3 1 * *Ngày 1 hàng tháng, 3h30 sáng
0 0 * * 0Mỗi Chủ nhật nửa đêm
# Ví dụ một dòng trong crontab
0 2 * * * /Users/you/bin/backup.sh >> /Users/you/logs/backup.log 2>&1
💡 Đừng học thuộc — dùng crontab.guru
crontab.guru dịch ngược cron expression sang tiếng Anh dễ hiểu, đồng thời preview lần chạy kế. Mỗi khi viết một dòng cron mới, paste nó vào đây trước khi save — tránh chạy 1 ngày 1 lần thay vì 1 phút 1 lần.
⚠️ Environment trong cron rất giới hạn
Job cron không kế thừa $PATH như shell tương tác. Lệnh node, brew, python3 rất dễ "không tìm thấy". Luôn dùng absolute path (vd /opt/homebrew/bin/node) hoặc set PATH=... ở đầu crontab.

3. launchd trên macOS

Apple khuyến nghị dùng launchd thay cho cron trên macOS. cron vẫn chạy được nhưng đã deprecated từ lâu. launchd quản lý cả daemon hệ thống lẫn job theo lịch của user — mỗi job là một file .plist (XML).

Vị tríDùng cho
~/Library/LaunchAgents/Job của user, chạy khi bạn login
/Library/LaunchAgents/Job cho mọi user
/Library/LaunchDaemons/Daemon hệ thống, chạy ngay cả khi chưa login

Plist tối thiểu — chạy script mỗi giờ

# File: ~/Library/LaunchAgents/com.you.hourly.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.you.hourly</string>

  <key>ProgramArguments</key>
  <array>
    <string>/Users/you/bin/hourly.sh</string>
  </array>

  <key>StartInterval</key>
  <integer>3600</integer>     <!-- 3600s = 1h -->

  <key>StandardOutPath</key>
  <string>/Users/you/logs/hourly.log</string>
  <key>StandardErrorPath</key>
  <string>/Users/you/logs/hourly.err</string>
</dict>
</plist>

Quản lý job

$ launchctl load   ~/Library/LaunchAgents/com.you.hourly.plist
$ launchctl list  | grep com.you
$ launchctl unload ~/Library/LaunchAgents/com.you.hourly.plist
$ launchctl start  com.you.hourly   # chạy ngay 1 lần để test

Mẹo: dùng StartCalendarInterval thay StartInterval để lên lịch theo giờ tuyệt đối (vd "mỗi đêm 2h"), giống cột giờ/phút của cron nhưng viết bằng XML.

4. systemd timer (Linux)

Đa số distro Linux hiện đại (Ubuntu, Debian, Fedora, Arch) dùng systemd. Thay vì cron, người ta dùng cặp file .service + .timer đặt trong /etc/systemd/system/. Bạn ít chạm trên macOS, nhưng khi SSH vào server Linux thì gần như chắc chắn gặp.

# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup every day at 02:00

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
$ sudo systemctl enable --now backup.timer
$ systemctl list-timers           # xem mọi timer + thời gian chạy kế
$ journalctl -u backup.service     # xem log của job

cron vs launchd vs systemd

Đặc điểmcronlaunchd (macOS)systemd (Linux)
Format1 dòng / jobXML plist2 file INI
LoggingPhải tự redirectStandardOutPathjournalctl tích hợp
Khởi động khi miss lịchKhôngCó (RunAtLoad)Có (Persistent=true)
Nền tảngMọi UnixChỉ macOSĐa số Linux modern
Độ phức tạpRất đơn giảnTrung bình (XML dài dòng)Trung bình

5. Logging & log rotation

Script tự động chạy nền — bạn không thấy output trên Terminal. Nếu không log lại, một ngày nó chết âm thầm và bạn không hề hay biết. Quy tắc: luôn redirect cả stdout và stderr ra file log có dấu thời gian.

# Trong script, hoặc ngay trong dòng cron:
$ ./backup.sh >> ~/logs/backup-$(date +%F).log 2>&1
#                                                  ^ stderr về cùng file stdout

Log file dồn lâu ngày sẽ ăn hết ổ cứng. Cần log rotation:

Hệ điều hànhTool rotateConfig ở đâu
Linuxlogrotate/etc/logrotate.d/yourapp
macOSnewsyslog/etc/newsyslog.d/yourapp.conf
# Ví dụ logrotate config — giữ 7 ngày, nén lại
/Users/you/logs/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
}

Nguyên tắc thực tế: log mỗi ngày 1 file, giữ 1-2 tuần, file cũ nén .gz. Quá đó thì xoá — bạn sẽ không bao giờ đọc log từ tháng trước.

6. Monitor & alert

Tự động hoá cao cấp = không chỉ chạy mà còn báo cho bạn biết khi có vấn đề. Kết hợp cron + curl + jq (Chương 8) + một kênh notification → bạn có một dashboard mini cho riêng mình.

Notification trên macOS

$ osascript -e 'display notification "Disk > 80%" with title "Cảnh báo"'

Slack webhook (nếu bạn xài Slack)

$ curl -X POST -H 'Content-Type: application/json' \
       -d '{"text":"Backup FAILED on $(hostname)"}' \
       https://hooks.slack.com/services/XXX/YYY/ZZZ

Health check + alert — script mẫu

#!/bin/bash
# check-disk.sh — cảnh báo nếu / vượt 80%
USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')

if [ "$USAGE" -gt 80 ]; then
  osascript -e "display notification \"Disk = ${USAGE}%\" with title \"Cảnh báo CLI\""
  echo "[$(date)] WARN: disk = ${USAGE}%" >> ~/logs/disk.log
fi

Check một API

$ curl -s https://api.example.com/health \
       | jq -r .status \
       | grep -q ok || osascript -e 'display notification "API down!" with title "ALERT"'

Đem 3 script trên + cron là bạn đã có một hệ thống monitor cá nhân. Không xịn bằng Datadog nhưng đủ để máy bạn không bao giờ bị "đầy ổ" giữa lúc deadline.

7. Thử ngay trong terminal giả lập

Simulator hỗ trợ vài lệnh demo của chương — thử chuỗi sau:

  1. Xem crontab hiện tại: crontab -l
  2. Liệt kê job launchd của bạn: launchctl list
  3. Xem lịch tiếp theo của các timer: systemctl list-timers
  4. Tạo folder chứa log: mkdir -p ~/logs
  5. Test redirect: date >> ~/logs/test.log 2>&1
  6. Đọc log: cat ~/logs/test.log
you@mac — chuong10 practice
you@mac ~ $

8. Bài tập về nhà

Trên Terminal thật — đây là chương cuối nên hãy làm ít nhất 6/9 bài:

  1. Tạo script ~/bin/backup.sh đóng gói ~/Documents ra ~/backup/$(date +%F).tar.gz. chmod +x rồi chạy thử.
  2. Thêm dòng cron chạy backup.sh mỗi giờ. Dùng crontab.guru xác nhận expression đúng.
  3. Đảm bảo log của job ghi ra ~/logs/backup.log với cả stderr (2>&1).
  4. Viết file ~/Library/LaunchAgents/com.you.nightly.plist chạy backup.sh mỗi đêm 2h sáng. Load + test bằng launchctl start.
  5. Viết script check-disk.sh: nếu phân vùng / > 80%, gửi notification bằng osascript. Schedule mỗi giờ.
  6. Viết script cleanup-downloads.sh xoá file trong ~/Downloads cũ hơn 30 ngày (find ~/Downloads -mtime +30 -delete). Schedule mỗi Chủ nhật 3h sáng.
  7. Trong cron có một job dùng node script.js nhưng báo lỗi "node: command not found". Tìm absolute path của node (which node) và sửa lại. Vì sao lỗi xảy ra?
  8. Đặt config logrotate (Linux) hoặc newsyslog (macOS) cho thư mục ~/logs giữ 7 ngày, nén file cũ.
  9. Bonus capstone: kết hợp mọi thứ đã học — viết một script theo dõi 3 thứ (disk, RAM bằng vm_stat, một API tuỳ chọn) rồi gửi notification khi có vấn đề. Schedule mỗi 15 phút.

9. Quiz — Kiểm tra kiến thức

10. Tổng kết khoá học 🎉

Bạn vừa đi xong 10 chương CLI Mastery. Hãy nhìn lại — bạn đã đi xa đến đâu rồi:

Bạn không còn là beginner. Bạn có thể mở Terminal trên bất kỳ Mac/Linux nào và làm việc ở đó — không cần GUI. Với người chưa biết CLI, đây là một siêu năng lực thật sự: tự động hoá những việc người khác phải làm thủ công mỗi ngày.

Bước kế tiếp — sau khoá học

🌱 Học không bao giờ dừng
Khoá học này kết thúc, nhưng CLI là một công cụ bạn sẽ dùng cả đời trong nghề dev/DevOps/data. Mỗi lần gặp vấn đề mới, đừng vội mở GUI — thử CLI trước. Mỗi khi gõ một lệnh, hỏi: "Có flag nào hay hơn không?". Đó là cách bạn đi từ "biết CLI" đến "thật sự thành thạo CLI". Hẹn gặp lại — và xin chúc mừng bạn đã hoàn thành khoá học! 🎉

← Quay về trang chủ và xem lại lộ trình

Trước ← Chương 09: Git & tooling Hoàn thành khoá học Quay về trang chủ 🎉