Shell Script เบื้องต้นสำหรับ sysadmin VPS
Shell script คือ automation ที่ทรงพลังที่สุดบน Linux VPS งานที่ต้องทำซ้ำๆ เช่น backup ตรวจ disk space ส่ง alert เมื่อ service หยุด หรือ cleanup log ล้วนทำเป็น script ได้ บทความนี้สอน Bash scripting ที่ sysadmin ใช้บ่อยที่สุด
โครงสร้าง Script พื้นฐาน
#!/bin/bash
# ทุก script ต้องขึ้นต้นด้วย shebang
# ออกทันทีเมื่อเจอ error (best practice)
set -euo pipefail
# ตัวแปร
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d)
LOG_FILE="/var/log/myscript.log"
echo "Script started at $(date)" | tee -a "$LOG_FILE"
Variables และ Conditions
# ตัวแปรและ argument
SITE_NAME="$1" # รับ argument แรก
DISK_THRESHOLD="${2:-80}" # default เป็น 80 ถ้าไม่ระบุ
# If/else
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt "$DISK_THRESHOLD" ]; then
echo "WARNING: Disk usage at ${DISK_USAGE}%"
# ส่ง alert email
echo "Disk usage: ${DISK_USAGE}%" | mail -s "Disk Alert: $(hostname)" [email protected]
else
echo "Disk OK: ${DISK_USAGE}%"
fi
Loops
# วน loop ผ่าน list
SITES=("site1.com" "site2.com" "site3.com")
for SITE in "${SITES[@]}"; do
echo "Backing up $SITE..."
mysqldump -u backup_user -p"$DB_PASS" "$SITE" > "/backup/${SITE}_${DATE}.sql"
done
# while loop
MAX_RETRIES=5
COUNT=0
while [ $COUNT -lt $MAX_RETRIES ]; do
if curl -sf "https://example.com" > /dev/null; then
echo "Site is up"
break
fi
COUNT=$((COUNT + 1))
sleep 5
done
Functions
# ประกาศ function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
check_service() {
local SERVICE="$1"
if systemctl is-active --quiet "$SERVICE"; then
log "$SERVICE is running"
return 0
else
log "ERROR: $SERVICE is not running"
systemctl start "$SERVICE"
return 1
fi
}
# ใช้ function
check_service nginx
check_service mysql
check_service php8.3-fpm
set -euo pipefail ตอนต้น script เสมอ: -e ออกทันทีเมื่อ command ล้มเหลว -u error ถ้าใช้ตัวแปรที่ยังไม่กำหนด -o pipefail ให้ pipe fail ถ้า command ใดๆ ใน pipe ล้มเหลว
ตรวจสอบว่า Shell Script ทำงานถูกต้อง
# ตรวจ syntax ก่อนรัน
bash -n myscript.sh
# รัน debug mode (แสดงทุก command ที่รัน)
bash -x myscript.sh
# ทดสอบด้วย shellcheck (lint tool)
sudo apt install shellcheck -y
shellcheck myscript.sh
# รัน script จริง
chmod +x myscript.sh
./myscript.sh
shellcheck เป็น linter ที่ดีมาก แนะนำ best practices และหาข้อผิดพลาดที่มองไม่เห็นได้ ควรรันก่อน deploy script ทุกครั้ง
แก้ปัญหาที่พบบ่อย
Script รันแล้ว "Permission denied"
ไฟล์ไม่มี execute permission ต้อง chmod ก่อน:
chmod +x script.sh
# หรือรันด้วย bash โดยตรง (ไม่ต้องการ execute permission)
bash script.sh
Script ทำงานบน terminal แต่ไม่ทำงานใน cron
cron มี PATH ที่จำกัดกว่า shell ปกติ ต้องระบุ full path ของคำสั่ง:
# ผิด (ใน cron PATH อาจหา wp ไม่เจอ)
wp core update
# ถูก
/usr/local/bin/wp core update
# หรือตั้ง PATH ตอนต้น script
export PATH="/usr/local/bin:/usr/bin:/bin:$PATH"
Script ออก exit code ไม่ถูกต้อง
ต้อง return exit code ที่ถูกต้องเพื่อให้ cron และ monitoring รู้ว่า success หรือ fail:
# ออกด้วย code ที่กำหนด
exit 0 # success
exit 1 # failure
# ตรวจ exit code ของคำสั่งที่รันก่อน
if ! mysqldump ...; then
log "Backup FAILED"
exit 1
fi
log "Backup SUCCESS"
exit 0
Variable ที่มี space ทำให้ command แตกออกเป็นหลาย argument
ต้อง quote ตัวแปรทุกครั้งที่ใช้:
# ผิด — ถ้า FILE="/path/to/my file.txt"
rm $FILE # แตกเป็น rm /path/to/my file.txt
# ถูก
rm "$FILE" # ทำงานถูกต้องแม้มี space
คำถามที่พบบ่อย
Bash กับ sh ต่างกันอย่างไร?
sh (POSIX shell) เป็น minimal shell ที่มีทุก Unix/Linux ทำงานได้ทุกที่แต่ฟีเจอร์จำกัด Bash มีฟีเจอร์มากกว่า เช่น arrays, [[ ]], process substitution สำหรับ script ที่ใช้บน server ที่รู้ว่ามี Bash อยู่แล้ว ใช้ Bash ได้เลย
จะ debug script ที่ fail ใน production ได้อย่างไร?
เพิ่ม set -x ที่ตอนต้นเพื่อ trace ทุก command ที่รัน redirect output ไปที่ log file: bash -x script.sh 2>&1 | tee /tmp/debug.log แล้วดู log หาบรรทัดที่ fail
Script ควรเก็บ password อย่างไร?
ไม่ควร hardcode password ใน script โดยตรง ใช้วิธีเหล่านี้แทน: 1) อ่านจาก environment variable ($DB_PASS) ที่ตั้งใน sudoer/cron environment 2) อ่านจาก config file ที่มี permission 600 3) ใช้ credentials helper เช่น secret manager