第 11 章 · Shell 脚本基础
本章目标:写可执行的 bash 脚本(shebang、chmod +x);使用变量、参数、if/for;理解 退出码;用 set -euo pipefail 避免脚本「错了还往下跑」;写 check_log.sh 对接 ch04/ch10 日志巡检。
学时建议:4~5 小时(含 2.5 小时跟练)
前置:linux-shell ch10;~/dev-workspace/shop-demo/scripts 目录存在(ch05/ch08)。
11.1 场景说明:每天手动 grep ERROR 太蠢
运维要求:「每个工作日早上看 api.log 有没有 ERROR,有就发消息。」
你可以:
- 每天手敲
grep ERROR ...(会忘) - 写 10 行脚本 + cron(ch12)自动跑
脚本 = 把你在 ch04~ch10 练过的命令按顺序写进文件,加判断(有没有 ERROR、退出码对不对)。
11.2 学完你能
| 能力 | 验收 |
|---|---|
| shebang + chmod | ./hello.sh 能跑 |
| 位置参数 | 读 $1 $# $@ |
| if/for | 文件不存在时 exit 非 0 |
| 退出码 | $? 与 exit 2 |
| set -euo | 解释三条各自防什么错 |
| 实用脚本 | check_log.sh 对 api.log 计数 ERROR |
11.3 第一个脚本:hello
步骤 1 — 写文件
mkdir -p ~/dev-workspace/shop-demo/scripts
cat > ~/dev-workspace/shop-demo/scripts/hello.sh << 'EOF'
#!/usr/bin/env bash
echo "Hello from shop-demo"
echo "User: $(whoami)"
echo "Date: $(date -Iseconds)"
EOF
步骤 2 — 赋予执行权限
chmod +x ~/dev-workspace/shop-demo/scripts/hello.sh
ls -l ~/dev-workspace/shop-demo/scripts/hello.sh
你应该看到:-rwxr-xr-x 含 x。
步骤 3 — 运行
~/dev-workspace/shop-demo/scripts/hello.sh
为什么 要 shebang #!/usr/bin/env bash:系统知道用 bash 解释,而不是 sh;为什么 要 chmod +x:否则只能 bash hello.sh 不能 ./hello.sh。
易错:Windows 编辑器保存 CRLF 会报 $'\r': command not found → 用 WSL 内 nano,或 dos2unix hello.sh。
11.4 变量与位置参数
步骤 1 — 写 args.sh
cat > ~/dev-workspace/shop-demo/scripts/args.sh << 'EOF'
#!/usr/bin/env bash
echo "Script name: $0"
echo "Argument count: $#"
echo "All arguments: $@"
echo "First arg: ${1:-<none>}"
EOF
chmod +x ~/dev-workspace/shop-demo/scripts/args.sh
步骤 2 — 运行
~/dev-workspace/shop-demo/scripts/args.sh foo bar
你应该看到:
Script name: .../args.sh
Argument count: 2
All arguments: foo bar
First arg: foo
读懂:
| 符号 | 含义 |
|---|---|
$0 | 脚本路径 |
$# | 参数个数 |
$@ | 全部参数 |
${1:-<none>} | 第一个参数,缺省为 <none> |
赋值:
API_PORT=8080
echo "port=$API_PORT"
注意:等号两边不能有空格。
11.5 退出码:脚本怎么表示成功/失败
命令跑完,Shell 用 退出码(0~255)表示结果:
grep ERROR ~/dev-workspace/logs/api.log
echo "exit code: $?"
| 码 | 常见含义 |
|---|---|
| 0 | 成功 |
| 1 | 一般错误(grep 无匹配也是 1) |
| 2+ | 脚本自定义 |
脚本里:
exit 0 # 成功
exit 1 # 失败
为什么 cron/systemd 靠退出码判断要不要告警。
11.6 set -euo pipefail(生产脚本标配)
在脚本第二行(shebang 后)常写:
set -euo pipefail
| 选项 | 防什么 |
|---|---|
-e | 任一命令失败(非 0)立即退出 |
-u | 使用未定义变量报错 |
-o pipefail | 管道里任一段失败,整条管道失败 |
演示 -u:
bash -c 'set -u; echo $NOT_DEFINED'
应报错。