echo "$1"$1、$2…按位置取参数,记得加双引号。
约 1350 字大约 5 分钟
2026-05-14
一个能复用的脚本,得能“接收输入”和“报告结果”。接收输入靠位置参数($1、$@),报告结果靠退出码(exit)。这两件事做好了,你的脚本才能被别的脚本调用、被定时任务调度、出错时被发现。
掌握位置参数 $1/$@/$#、参数校验,以及用退出码向调用者报告成败,让脚本能被可靠地复用和编排。
echo "$1"$1、$2…按位置取参数,记得加双引号。
echo "$@"$@ 加引号是“每个参数各自完整”,遍历参数用它。
echo "$#"用来校验:参数不够就报错退出。
exit 10 表示成功,非 0 表示失败,调用者据此判断。
调用 ./backup.sh /data /backup 时,脚本内部:
| 变量 | 值 | 含义 |
|---|---|---|
$0 | ./backup.sh | 脚本自己的名字 |
$1 | /data | 第一个参数 |
$2 | /backup | 第二个参数 |
$# | 2 | 参数个数 |
$@ | /data /backup | 全部参数 |
引用参数和引用变量一样,加双引号:"$1"。遍历所有参数用 "$@":
for arg in "$@"; do
echo "收到参数:$arg"
done"$@"(带引号)和 $@(不带)有微妙但重要的区别:带引号时,每个参数保持完整(哪怕里面有空格);不带引号会被重新拆分。永远用 "$@"。
脚本最常见的事故,是参数不对还硬着头皮执行。开头就校验:
#!/usr/bin/env bash
if [ "$#" -lt 2 ]; then
echo "用法:$0 <源目录> <目标目录>" >&2
exit 1
fi
src="$1"
dst="$2"
if [ ! -d "$src" ]; then
echo "错误:源目录 $src 不存在" >&2
exit 1
fi要点:参数个数不对、目录不存在这类问题,早发现早退出,并且把错误信息打到 stderr(>&2),退出码用非 0。带着错误的输入往下执行,后果往往比直接报错严重得多。
脚本结束时用 exit 留下一个退出码,这是它对调用者说的“我成没成”:
exit 0 # 成功
exit 1 # 失败(通用)
# 不写 exit,脚本的退出码是最后一条命令的退出码为什么重要:退出码是脚本能被编排的基础。./a.sh && ./b.sh 里,b.sh 跑不跑取决于 a.sh 的退出码;定时任务、CI、监控判断脚本成没成,全看退出码——它们不会去读你打印的文字(退出码的通用概念见 命令、参数与退出码)。
所以脚本里检测到错误,一定要 exit 非0,而不是打印一句“出错了”然后正常结束——后者会让调用者以为成功了。
写脚本时遵守一些约定,它就能像一个正经命令一样被使用:
-h 打印用法exit 0,各种失败用不同的非 0 码参数直接用进危险命令前,务必校验
脚本最危险的组合是“外部传入的参数”直接拼进 rm、mv、chown 这类命令。比如 rm -rf "$1/",调用者忘了传参数时 $1 为空,就变成了 rm -rf /。防护:① 危险操作前校验参数非空、路径存在([ -n "$1" ]、[ -d "$1" ]);② 配合 set -euo pipefail 的 set -u,用到未定义变量直接报错;③ 涉及删除、覆盖的脚本,先用 echo 预览实际命令。
| 误区 | 更稳妥的做法 |
|---|---|
用 $@ 不加引号遍历参数 | 用 "$@",带空格的参数才不会被拆开 |
| 脚本不校验参数就往下跑 | 开头校验 $# 和参数有效性,不对就 exit 1 |
出错只 echo 一句然后正常结束 | 必须 exit 非0,否则调用者以为成功了 |
| 错误信息和正常结果都打到 stdout | 错误打到 stderr(>&2),便于调用者区分 |
版权归属:Shuo Liu