主题
13 · 循环、函数与脚本结构
目标:用
for/while、函数与source把脚本拆成可读结构。
前置:12 · 变量与条件
1. 环境前提
bash
mkdir -p ~/lab/scripts/lib ~/lab/logs1
2. for / while
bash
# 遍历参数
for f in "$@"; do
echo "arg=$f"
done
# 遍历文件
for f in "$HOME"/lab/scripts/*.sh; do
[[ -e "$f" ]] || continue
echo "script: $f"
done
# 计数
i=1
while [[ $i -le 3 ]]; do
echo "i=$i"
i=$((i + 1))
done1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
读文件行(注意最后一行无换行时的边界;运维日志够用):
bash
while IFS= read -r line || [[ -n "$line" ]]; do
echo "line=$line"
done < /etc/hostname1
2
3
2
3
3. 函数
bash
cat > ~/lab/scripts/lib/log.sh <<'EOF'
#!/usr/bin/env bash
# 可被 source 的日志函数(不要直接执行本文件当主程序)
log() {
local level="$1"
shift
printf '%s [%s] %s\n' "$(date -Is)" "$level" "$*"
}
log_info() { log INFO "$@"; }
log_error() { log ERROR "$@" >&2; }
EOF1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
主脚本:
bash
cat > ~/lab/scripts/demo-struct.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/log.sh
source "$SCRIPT_DIR/lib/log.sh"
usage() {
echo "用法: $0 <名字>" >&2
}
main() {
if [[ $# -lt 1 ]]; then
usage
exit 2
fi
log_info "hello, $1"
}
main "$@"
EOF
chmod 755 ~/lab/scripts/demo-struct.sh
~/lab/scripts/demo-struct.sh World1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
要点:
| 点 | 说明 |
|---|---|
local | 函数内局部变量 |
"$@" 传给 main | 保留参数边界 |
BASH_SOURCE[0] | 当前脚本路径(比 $0 在 source 场景更稳) |
source / . | 在当前 shell 加载函数库 |
4. 推荐目录结构(本系列)
text
~/lab/scripts/
lib/
log.sh
hello.sh
greet.sh
demo-struct.sh
healthcheck.sh # 14
backup-lab.sh # 15
cleanup-logs.sh # 15
~/lab/logs/ # 脚本运行日志
~/lab/backups/ # 备份产物1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
5. 数组(够用即可)
bash
hosts=("127.0.0.1" "localhost")
for h in "${hosts[@]}"; do
echo "host=$h"
done1
2
3
4
2
3
4
6. 动手清单
- [ ] 写循环列出
~/lab/scripts/*.sh - [ ]
lib/log.sh+demo-struct.sh跑通 - [ ] 故意不传参,确认 usage + 退出码 2
- [ ] 能口述:
source与「新开 bash 跑脚本」的区别(变量/函数是否留下)
7. 常见翻车
| 翻车 | 处理 |
|---|---|
for f in *.sh 无匹配时留下字面量 *.sh | 先 shopt -s nullglob 或 [[ -e "$f" ]] || continue |
| 函数里改全局变量难查 | 尽量 local |
source 路径写错 | 用 SCRIPT_DIR 拼绝对路径 |
在库文件末尾执行 main | 库只定义函数;入口脚本调 main |
8. 官方入口
- Bash Looping Constructs
- Shell Functions
help for、help source
下一篇:运维脚本 —— 健康检查失败则重启 mini-api。
