Shell 腳本是 Linux/Unix 系統管理、自動化運維、資料處理的基石。掌握經典範例模式,能快速解決實際問題。本文精選 8 個實用腳本,涵蓋輸入驗證、數學運算、參數處理、檔案操作、磁碟管理、配置解析、正則驗證、備份策略,並解析關鍵語法與最佳實踐。
#!/bin/bash
# 腳本: check_input.sh
read -p "請輸入數字、字母或其他: " input
case $input in
[0-9]) echo "✓ 輸入為數字" ;;
[a-zA-Z]) echo "✓ 輸入為字母" ;;
*) echo "✗ 輸入非預期類型,請重試" ;;
esac
關鍵點:case 模式匹配支援字符類 [0-9]、[a-zA-Z];*) 為預設分支。注意:單字符匹配,多字符需用 [0-9]* 或正則 =~。
#!/bin/bash
# 腳本: average.sh
SCORE=0
SUM=0
COUNT=0
while true; do
read -p "請輸入分數 (0-100, q 結束): " SCORE
# 退出條件
[[ "$SCORE" == "q" || "$SCORE" == "Q" ]] && break
# 數值驗證
if ! [[ "$SCORE" =~ ^[0-9]+$ ]] || (( SCORE < 0 || SCORE > 100 )); then
echo "✗ 輸入無效,請輸入 0-100 的整數"
continue
fi
(( SUM += SCORE ))
(( COUNT++ ))
AVG=$(( SUM / COUNT ))
echo "當前平均: $AVG (共 $COUNT 筆)"
done
echo "最終平均: $AVG"
echo "程式結束"
關鍵點:(( ... )) 算術擴展支援 C 風格運算;[[ ... ]] 條件判斷支援正則 =~;read -p 合併提示與讀取。
shift 實戰
#!/bin/bash
# 腳本: shift_demo.sh
# 用法: ./shift_demo.sh a b c d e
echo "參數總數: $#"
echo "所有參數: $*"
while (( $# > 0 )); do
echo "剩餘參數: $*"
shift # 移除 $1,所有參數左移
done
執行結果:
$ ./shift_demo.sh a b c d e
參數總數: 5
所有參數: a b c d e
剩餘參數: a b c d e
剩餘參數: b c d e
剩餘參數: c d e
剩餘參數: d e
剩餘參數: e
應用場景:處理不定數量位置參數、解析命令列選項 (配合 case $1 in)。
#!/bin/bash
# 腳本: add_prefix.sh
# 準備: namelist.txt 每行一個名字
INPUT_FILE="namelist.txt"
PREFIX="USER_"
if [[ ! -f "$INPUT_FILE" ]]; then
echo "✗ 找不到 $INPUT_FILE"
exit 1
fi
while IFS= read -r name; do
# 跳過空行與註解
[[ -z "$name" || "$name" =~ ^# ]] && continue
echo "${PREFIX}${name}"
done < "$INPUT_FILE"
關鍵點:while IFS= read -r line; done < file 是讀取檔案每行的標準模式,保留前導/尾隨空格、不解析反斜線。IFS= 防止欄位分割。
#!/bin/bash
# 腳本: check_files.sh
for file in test*.sh; do
# 避免無匹配時字面字串 "test*.sh"
[[ -e "$file" ]] || continue
echo "✓ 存在: $file"
done
# 進階: 檢查指定清單
FILE_LIST=("config.yaml" "app.log" "data.csv" "backup.tar.gz")
for f in "${FILE_LIST[@]}"; do
if [[ -f "$f" ]]; then
echo "✓ 檔案存在: $f"
else
echo "✗ 檔案缺失: $f"
fi
done
注意:for file in pattern 無匹配時會字面迭代模式字串,需 [[ -e "$file" ]] || continue 過濾。
#!/bin/bash
# 腳本: fill_disk.sh
# ⚠️ 僅用於測試環境,謹慎使用!
TARGET_DIR="/tmp/fill_test"
MAX_FILES=3800
FILE_SIZE_MB=1
COUNTER=0
mkdir -p "$TARGET_DIR"
# 建立 1MB 測試檔
dd if=/dev/zero of="$TARGET_DIR/testfile" bs=1M count=$FILE_SIZE_MB 2>/dev/null
while (( COUNTER < MAX_FILES )); do
(( COUNTER++ ))
# 每 1000 個報告進度
if (( COUNTER % 1000 == 0 )); then
echo "[$(date)] 已建立 $COUNTER 個檔案"
fi
cp "$TARGET_DIR/testfile" "$TARGET_DIR/file_${COUNTER}.dat" 2>/dev/null || {
echo "✗ 磁碟空間不足,停止於 $COUNTER"
break
}
done
echo "完成,共建立 $COUNTER 個檔案"
# 清理: rm -rf "$TARGET_DIR"
關鍵點:dd 建立固定大小檔案;cp 複製比重複 dd 快;錯誤輸出導向 /dev/null;|| { ... } 處理失敗情況。
#!/bin/bash
# 腳本: parse_config.sh
# 配置檔: hosts.allow 每行一個 IP
CONFIG_FILE="hosts.allow"
declare -a HOSTS
INDEX=0
# 讀取每行到陣列
while IFS= read -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
HOSTS[INDEX]="$line"
(( INDEX++ ))
done < "$CONFIG_FILE"
# 遍歷陣列 (注意索引從 0 開始)
for (( i=0; i<${#HOSTS[@]}; i++ )); do
echo "允許主機 [$i]: ${HOSTS[i]}"
done
echo "共讀取 ${#HOSTS[@]} 條記錄"
關鍵點:declare -a 宣告陣列;${#ARR[@]} 獲取長度;${ARR[i]} 存取元素。Bash 陣列索引從 0 開始。
#!/bin/bash
# 腳本: validate.sh
REGEX='^[A-Za-z0-9]{6}$'
if [[ $1 =~ $REGEX ]]; then
echo "✓ 驗證通過: $1"
exit 0
else
echo "✗ 驗證失敗: 輸入必須為 6 位英數字"
exit 1
fi
#!/bin/bash
# 腳本: backup.sh
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="/backup/backup_${DATE}.tar.gz"
SRC_DIRS="/home /etc /var/www"
echo "開始備份至 $BACKUP_FILE ..."
tar -czf "$BACKUP_FILE" $SRC_DIRS 2>/dev/null
if [[ $? -eq 0 ]]; then
echo "✓ 備份成功: $BACKUP_FILE"
# 可選: 刪除 7 天前備份
find /backup -name "backup_*.tar.gz" -mtime +7 -delete
else
echo "✗ 備份失敗"
exit 1
fi
關鍵修正:原文 tar xcvf 為解壓縮參數,備份應用 tar -czf (建立、gzip、檔案)。
| 原則 | 做法 |
|---|---|
| Shebang | 固定使用 #!/bin/bash (或 #!/usr/bin/env bash 跨平台) |
| 錯誤處理 | 開頭加 set -euo pipefail (變數未設定報錯、命令失敗退出、管道失敗傳遞) |
| 變數引用 | 總是雙引號 "$VAR" 防止分詞與展開 |
| 迴圈讀檔 | 標準模式 while IFS= read -r line; do ... done < file |
| 算術運算 | 使用 (( ... )) 或 $(( ... )) |
| 條件判斷 | 優先 [[ ... ]] (支援正則、模式匹配、邏輯運算) |
| 函數化 | 將邏輯封裝為函數,主流程清晰 |
| 日誌輸出 | 統一 log_info()/log_error() 函數,含時間戳 |
| 臨時檔案 | 使用 mktemp,退出時 trap 'rm -f $TMP' EXIT 清理 |
| 測試驗證 | 使用 shellcheck 靜態分析,bats 單元測試 |
這 8 個腳本涵蓋了 Shell 程式設計的核心模式:輸入處理、迴圈控制、參數操作、檔案遍歷、資源壓測、配置解析、正則驗證、備份自動化。理解每個範例背後的語法機制 (case/shift/read/for/while/[[ =~ ]]/陣列/date/tar),並遵循最佳實踐 (set -euo pipefail、雙引號變數、標準讀檔模式),就能將這些模板快速適配到實際運維、部署、監控、資料處理任務中。Shell 的威力在於無處不在、零依賴、直呼系統介面,掌握它是每個後端工程師、運維工程師的必修課。