安全获取参数必须用"$1"而非$1,因双引号防止空格截断和通配符展开;判断为空用[ -z "$1" ];默认值写为${1:-"default"};遍历参数始终用"$@"而非"$*";解析选项优先用getopts处理短选项组合与参数校验。

直接用 $1、$2 就能取到参数,但不加引号或混淆 $* 与 $@ 会导致空格截断、通配符展开等意外行为。
怎么安全获取第一个参数
用 "$1",而不是 $1 —— 双引号不是可选项,是保命操作。如果用户执行 ./deploy.sh "/path/to/my app",没引号时 $1 会被拆成 /path/to/my 和 app 两个词,$2 才是 app,逻辑全乱。
- 始终用
"$1"、"$2"这类带双引号的写法 - 检查是否传了:用
[ -z "$1" ]判断为空,比[ -z $1 ]安全(后者在$1为空时会变成[ -z ],语法错误) - 需要默认值?写成
name=${1:-"default"},冒号表示“未设置或为空”都触发
遍历所有参数该用 "$@" 还是 "$*"
99% 的场景该用 "$@"。它把每个参数当独立字符串保留原始边界;"$*" 把所有参数拼成一个字符串,中间只用空格连接,会丢失结构。
- 正确遍历:
for arg in "$@"; do echo "got: $arg"; done - 错误示范:
for arg in "$*"; do ...—— 即使你传了"a b" "c d","$*"也只给你一个"a b c d" - 调试时可加
printf '%q ' "$@"; echo查看实际分词结果(%q会转义空格和引号)
为什么 getopts 比手工解析更可靠
因为 getopts 自动处理短选项组合(如 -avf)、选项后必带参数(-o file.txt)、缺失参数报错、以及提前终止解析(遇到 -- 后停止)。
- 基础用法:
while getopts "hvf:" opt; do case $opt in h) echo "help";; v) verbose=1;; f) file="$OPTARG";; *) echo "bad option"; exit 1;; esac; done -
f:中的冒号表示-f必须跟值,getopts会自动把值赋给$OPTARG - 别用
getopts解析长选项(--verbose),那是getopt(注意末尾多一个t)的活
容易被忽略的陷阱:数组传参和子 shell 环境
在函数里调用 "$@" 是安全的,但如果你用 sh script.sh 方式执行脚本(而非 ./script.sh 或 bash script.sh),shebang 行会被忽略,$0 变成 sh,且某些老版本 sh 不支持 "$@" —— 它只认 $*。
- 确保脚本第一行是
#!/bin/bash,并用./script.sh执行,避免掉进 POSIXsh兼容坑 - 函数内要转发全部参数?直接写
next_func "$@",不要写成next_func "$*"或next_func $@ - 用
set -- new1 new2可以重置位置参数,但注意这会影响整个当前 shell 环境,慎用于 sourced 脚本










