5.2.4 参数传递与位置参数($0-$9、$@、$#、$?)
在 Shell 脚本中,参数传递依赖位置参数机制。脚本被调用时,命令行中的参数会按顺序赋值给 $1 到 $9,脚本名称自身为 $0。当参数超过 9 个时,需要使用花括号形式 ${10}、${11} 访问更高位参数。$@ 与 $* 都表示所有位置参数,但语义不同:"$@" 会保留每个参数的独立性,常用于循环遍历;"$*" 会将所有参数合并为一个字符串,常用于整体输出。$# 表示参数个数,用于校验。$? 表示上一条命令或函数的退出状态码,0 为成功,非 0 为失败。
安装/环境确认(脚本依赖 Bash):
# 检查系统是否已安装 Bash
which bash
bash --version
# 预期:输出 bash 路径与版本号
完整可执行示例(保存为 /opt/scripts/args_demo.sh):
#!/usr/bin/env bash
# 用法: ./args_demo.sh <src> <dst> [--dry-run] [extra...]
echo "脚本名: $0"
echo "参数个数: $#"
# 参数数量校验
if [ $# -lt 2 ]; then
echo "usage: $0 <src> <dst> [--dry-run] [extra...]"
exit 1
fi
src="$1"
dst="$2"
# 处理可选参数:示范 shift
shift 2
dry_run=0
for arg in "$@"; do
if [ "$arg" = "--dry-run" ]; then
dry_run=1
fi
done
echo "src=$src"
echo "dst=$dst"
echo "dry_run=$dry_run"
# 安全遍历参数
echo "遍历所有参数($@):"
for arg in "$@"; do
echo " -> $arg"
done
# 示例操作:检查路径
if [ ! -e "$src" ]; then
echo "ERROR: src 不存在"
exit 2
fi
# 运行演示命令
if [ "$dry_run" -eq 1 ]; then
echo "DRY-RUN: cp -a \"$src\" \"$dst\""
else
cp -a "$src" "$dst"
fi
# 检查上一条命令状态码
if [ $? -ne 0 ]; then
echo "复制失败"
exit 3
fi
echo "完成"
运行与预期效果:
chmod +x /opt/scripts/args_demo.sh
# 正常运行
/opt/scripts/args_demo.sh /etc/hosts /tmp/hosts.bak --dry-run foo bar
# 预期输出:展示脚本名、参数数量、src/dst、dry_run=1、参数遍历
关键命令解释:
- "$@":逐个保留参数,用于 for 遍历;安全处理包含空格的参数。
- "$*":合并为单个字符串,适合一次性输出。
- shift 2:丢弃前 2 个位置参数,将可选参数前移便于解析。
- $?:判断上一条命令是否执行成功,用于错误处理。
排错清单:
1. 报 “permission denied”:未授权执行脚本
处理:chmod +x /opt/scripts/args_demo.sh
2. 参数包含空格导致断行:未使用 "$@"
处理:遍历参数时使用 for arg in "$@"; do ...
3. 参数不足导致脚本异常:未校验 $#
处理:在脚本开头加入参数数量校验并 exit 1
4. ${10} 被解析错误:未使用花括号
处理:使用 ${10}、${11} 形式
练习:
1. 扩展脚本,新增参数 --force,当目标存在时允许覆盖并输出提示。
2. 使用 $* 与 $@ 各输出一次,对比含空格参数的差异。
3. 增加一个校验:当 src 不是文件时返回退出码 4。
4. 将 cp 改为 rsync -a,并在失败时打印 $? 的值。