Ubuntu 22.04 Shell Script 自動化腳本

Ubuntu 22.04 Shell Scripting Automation

本文將介紹在 Ubuntu 22.04 環境下撰寫 Shell Script 的完整指南,從基礎語法到進階技巧,幫助你實現系統管理自動化。

Shell Script 基礎

Shell Script 是一種命令列直譯器腳本,在 Linux 系統中最常用的是 Bash(Bourne Again Shell)。

建立第一個腳本

1
2
3
#!/bin/bash
# 這是我的第一個 Shell Script
echo "Hello, Ubuntu 22.04!"

儲存為 hello.sh 後,需要賦予執行權限:

1
2
chmod +x hello.sh
./hello.sh

變數與參數

變數宣告與使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash
# 變數宣告(等號前後不能有空格)
NAME="Ubuntu"
VERSION="22.04"

# 使用變數
echo "系統名稱: $NAME"
echo "版本號碼: ${VERSION}"

# 唯讀變數
readonly SYSTEM_NAME="Linux"

# 環境變數
export MY_PATH="/usr/local/bin"

位置參數

1
2
3
4
5
6
7
8
#!/bin/bash
# 位置參數範例
echo "腳本名稱: $0"
echo "第一個參數: $1"
echo "第二個參數: $2"
echo "所有參數: $@"
echo "參數個數: $#"
echo "上一個命令的退出狀態: $?"

特殊變數

變數說明
$0腳本名稱
$1-$9位置參數
$#參數個數
$@所有參數(分開)
$*所有參數(合併)
$$目前程序 PID
$?上一個命令的退出狀態

條件判斷

if-else 語句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
FILE="/etc/passwd"

if [ -f "$FILE" ]; then
    echo "檔案 $FILE 存在"
elif [ -d "$FILE" ]; then
    echo "$FILE 是一個目錄"
else
    echo "檔案 $FILE 不存在"
fi

數值比較運算子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash
NUM1=10
NUM2=20

if [ $NUM1 -eq $NUM2 ]; then
    echo "相等"
elif [ $NUM1 -lt $NUM2 ]; then
    echo "$NUM1 小於 $NUM2"
elif [ $NUM1 -gt $NUM2 ]; then
    echo "$NUM1 大於 $NUM2"
fi
運算子說明
-eq等於
-ne不等於
-lt小於
-le小於等於
-gt大於
-ge大於等於

case 語句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/bin/bash
read -p "請輸入選項 (1-3): " OPTION

case $OPTION in
    1)
        echo "你選擇了選項 1"
        ;;
    2)
        echo "你選擇了選項 2"
        ;;
    3)
        echo "你選擇了選項 3"
        ;;
    *)
        echo "無效的選項"
        ;;
esac

迴圈結構

for 迴圈

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
# 基本 for 迴圈
for i in 1 2 3 4 5; do
    echo "數字: $i"
done

# C 風格 for 迴圈
for ((i=0; i<5; i++)); do
    echo "計數: $i"
done

# 遍歷檔案
for file in /var/log/*.log; do
    echo "日誌檔案: $file"
done

while 迴圈

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
COUNT=1

while [ $COUNT -le 5 ]; do
    echo "第 $COUNT 次迴圈"
    ((COUNT++))
done

# 讀取檔案內容
while IFS= read -r line; do
    echo "行內容: $line"
done < "/etc/hosts"

until 迴圈

1
2
3
4
5
6
7
#!/bin/bash
NUM=1

until [ $NUM -gt 5 ]; do
    echo "數字: $NUM"
    ((NUM++))
done

函數定義

基本函數

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# 定義函數
say_hello() {
    echo "你好,$1!"
}

# 帶有回傳值的函數
add_numbers() {
    local result=$(($1 + $2))
    echo $result
}

# 呼叫函數
say_hello "使用者"

# 取得函數回傳值
SUM=$(add_numbers 10 20)
echo "總和: $SUM"

函數中的區域變數

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
GLOBAL_VAR="全域變數"

my_function() {
    local LOCAL_VAR="區域變數"
    echo "函數內: $LOCAL_VAR"
    echo "函數內存取全域: $GLOBAL_VAR"
}

my_function
echo "函數外: $GLOBAL_VAR"
# echo $LOCAL_VAR  # 這會是空的

輸入輸出重導向

基本重導向

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
# 標準輸出重導向到檔案(覆蓋)
echo "這是測試內容" > output.txt

# 標準輸出重導向到檔案(附加)
echo "附加的內容" >> output.txt

# 標準錯誤重導向
ls /nonexistent 2> error.log

# 同時重導向標準輸出和錯誤
command > output.txt 2>&1

# 使用 /dev/null 丟棄輸出
command > /dev/null 2>&1

Here Document

1
2
3
4
5
6
7
#!/bin/bash
cat << EOF > config.txt
伺服器設定檔
主機名稱: $(hostname)
日期: $(date)
使用者: $USER
EOF

管道操作

1
2
3
4
5
6
#!/bin/bash
# 使用管道串接命令
ps aux | grep nginx | awk '{print $2}'

# 計算檔案行數
cat /etc/passwd | wc -l

錯誤處理

檢查命令執行結果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
# 使用 $? 檢查
apt update
if [ $? -ne 0 ]; then
    echo "更新失敗" >&2
    exit 1
fi

# 使用 || 和 && 運算子
mkdir /tmp/mydir && echo "目錄建立成功" || echo "目錄建立失敗"

set 指令選項

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
# 遇到錯誤立即退出
set -e

# 使用未定義變數時報錯
set -u

# 管道中任一命令失敗則整體失敗
set -o pipefail

# 常用組合
set -euo pipefail

trap 捕捉訊號

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
# 清理函數
cleanup() {
    echo "執行清理工作..."
    rm -f /tmp/tempfile_$$
    exit
}

# 捕捉退出訊號
trap cleanup EXIT INT TERM

# 建立暫存檔案
echo "測試" > /tmp/tempfile_$$
echo "腳本執行中..."
sleep 5

常用範例腳本

系統資訊腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# system_info.sh - 顯示系統資訊

echo "========== 系統資訊 =========="
echo "主機名稱: $(hostname)"
echo "作業系統: $(lsb_release -d | cut -f2)"
echo "核心版本: $(uname -r)"
echo "目前時間: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
echo "========== 硬體資訊 =========="
echo "CPU: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d':' -f2)"
echo "記憶體: $(free -h | awk '/^Mem:/ {print $2}')"
echo "磁碟使用率:"
df -h | grep '^/dev'
echo ""
echo "========== 網路資訊 =========="
echo "IP 位址:"
ip -4 addr show | grep inet | awk '{print $2}'

備份腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# backup.sh - 自動備份腳本

set -euo pipefail

# 設定變數
BACKUP_DIR="/backup"
SOURCE_DIR="/var/www"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="backup_${DATE}.tar.gz"

# 檢查備份目錄
[ -d "$BACKUP_DIR" ] || mkdir -p "$BACKUP_DIR"

# 執行備份
echo "開始備份 $SOURCE_DIR..."
tar -czf "${BACKUP_DIR}/${BACKUP_FILE}" "$SOURCE_DIR"

# 刪除 7 天前的備份
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +7 -delete

echo "備份完成: ${BACKUP_DIR}/${BACKUP_FILE}"

日誌監控腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
# log_monitor.sh - 監控日誌檔案

LOG_FILE="/var/log/syslog"
KEYWORD="error"

tail -f "$LOG_FILE" | while read line; do
    if echo "$line" | grep -qi "$KEYWORD"; then
        echo "[警告] $(date '+%H:%M:%S') - 發現錯誤: $line"
        # 可在此加入通知機制
    fi
done

腳本除錯技巧

使用 -x 選項

1
2
3
4
5
6
#!/bin/bash -x
# 或在腳本中使用 set -x

set -x  # 開啟除錯模式
echo "這行會顯示執行過程"
set +x  # 關閉除錯模式

使用 -v 選項

1
2
3
#!/bin/bash -v
# 顯示腳本每一行內容
echo "Hello"

自訂除錯函數

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
DEBUG=true

debug_log() {
    if [ "$DEBUG" = true ]; then
        echo "[DEBUG] $(date '+%H:%M:%S') - $1" >&2
    fi
}

debug_log "開始執行腳本"
# 執行其他操作
debug_log "腳本執行完成"

常用除錯技巧

  1. 使用 bash -n script.sh 檢查語法錯誤
  2. 使用 shellcheck script.sh 進行靜態分析
  3. 在關鍵位置加入 echo 輸出變數值
  4. 使用 trap 'echo "Line $LINENO"' DEBUG 追蹤執行位置

參考資料

透過本文的學習,你應該已經掌握了在 Ubuntu 22.04 上撰寫 Shell Script 的基本技能。建議從簡單的腳本開始練習,逐步挑戰更複雜的自動化任務。

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy