函式
函式把一段邏輯取名字。腳本變長、同一段檢查出現第二次時,就該拆出來。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 當回傳值
用結束碼當布林值時,函式裡最後那道 [[ ]] 或 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 表示資料。把這些拼起來的完整腳本見 實用範例。