跳轉到

建立 2026-09-14 更新 2026-09-14

函式

函式把一段邏輯取名字。腳本變長、同一段檢查出現第二次時,就該拆出來。Bash 函式與其他語言不同的地方:參數還是 $1 $2,回傳主要靠結束碼,印到 stdout 才是「回傳值」。

定義與呼叫

log() {
  echo "[$(date +%H:%M:%S)] $*"
}

die() {
  echo "錯誤:$*" >&2
  exit 1
}

log "開始備份"
[[ -d $HOME ]] || die "沒有家目錄"

呼叫時不要(),那是定義才寫。log "開始備份" 裡的字串會變成函式內的 $1

範圍

prefix="app"

build_name() {
  local suffix=$1
  echo "${prefix}-${suffix}"
}

name=$(build_name 2026-09-14)
  • 沒宣告 local 的變數是全域,函式裡一改,外面也跟著變
  • 需要的輸入用參數傳,不要依賴一堆全域變數
  • name=$(build_name ...) 用 stdout 當回傳值
is_root() {
  [[ $(id -u) -eq 0 ]]
}

if is_root; then
  echo "正在以 root 執行"
fi

用結束碼當布林值時,函式裡最後那道 [[ ]]return 0 / return 1 即可。return 結束的是函式,exit 結束的是整個腳本。

小而完整的骨架

#!/usr/bin/env bash
set -euo pipefail

usage() {
  echo "用法:$0 <來源> <目的>" >&2
  exit 2
}

main() {
  [[ $# -eq 2 ]] || usage
  local src=$1 dest=$2
  [[ -e $src ]] || { echo "找不到 $src" >&2; exit 1; }
  cp -a -- "$src" "$dest"
  echo "已複製到 $dest"
}

main "$@"

最後一行 main "$@" 把命令列參數原封傳進函式。好處是:定義都在上面,真正開始跑的入口只有一處,之後要 source 這個檔來測函式也比较容易。

總結

函式用 $1 接參數、local 避免污染全域、結束碼表示成敗、stdout 表示資料。把這些拼起來的完整腳本見 實用範例