特殊变量和位置参数是Shell脚本可靠运行的底层支撑,用于自省、状态追踪、安全传参与参数校验。$0、$?、$$分别标识脚本路径、上条命令状态和当前PID;$1~$9、$@、$*、$#支持安全接收、透传及校验用户输入;需注意"$@"与"$*"差异、$?局限性及$$与$BASHPID区别。
Shell脚本中,特殊变量(如
、
、
)和位置参数(
、
…
、
、
)不是语法糖,而是运维自动化脚本可靠运行的底层支撑。它们让脚本能自感知执行上下文、安全响应外部输入、准确判断执行结果。
用
、
、
实现脚本自省与状态追踪
脚本需要知道自己是谁、谁调用了它、执行是否成功、当前进程是否唯一——这些都依赖特殊变量。
是脚本自身路径,常用于日志记录或构建相对路径:
log_file="$(dirname "$0")/run.log"
保存上一条命令退出状态,必须在命令后立即使用,否则会被覆盖:
rm /tmp/data.txt && echo "clean ok" || { echo "rm failed: $?"; exit 1; }
是当前shell进程PID,可用于生成临时文件名或加锁防止并发:
lockfile="/tmp/backup.$$.lock"; trap 'rm -f "$lockfile"' EXIT
用
到
、
、
安全接收并处理用户输入
位置参数是脚本与外界交互的入口,但直接使用
等易出错,需配合校验与引号包裹。
始终用双引号包裹:避免空格或通配符被意外展开,
cp "$1" /backup/
比
cp $1 /backup/
安全得多
按原始参数个数和边界逐一分割,适合透传参数:
rsync -av "$@" /data/
—— 调用
./sync.sh -z --delete /src/
时,每个选项独立传递
把所有参数拼成单字符串(以
首个字符分隔),仅在需合并为一句日志时使用:
echo "Called with: $*" >> audit.log
用
和条件判断实现参数合法性控制
运维脚本常因参数缺失导致误操作,
是参数计数器,是参数校验的第一道防线。
检查必需参数数量:
[ $# -lt 2 ] && { echo "Usage: $0"; exit 2; }
结合
支持可选参数时,仍可用
判断剩余非选项参数是否充足:
while getopts "p:t:" opt; do ...; done; shift $((OPTIND-1)); [ $# -eq 0 ] && die "Missing target path"
避免硬编码参数个数,用
代替
——后者无法区分
和
实战中容易忽略的关键细节
这些变量行为看似简单,但在复杂场景下极易踩坑。
和
在双引号内行为不同:
"$@"
→
("a b" "c d")
;
"$*"
→
("a b c d")
(空格连接)
只反映**最后一条命令**的退出码,管道中要用
获取各段状态:
cmd1 | cmd2 | cmd3; [ ${PIPESTATUS[0]} -ne 0 ] && echo "cmd1 failed"
子shell中
不变,但
(bash特有)会变,需区分进程ID用途:
echo "parent $$, subshell $$, real pid $BASHPID"
$0$?$$$1$2$@$*$#$0$?$$$0$?$$$1$9$@$*$1$@$*$IFS$#$#getopts$#[ $# -eq 0 ][ -z "$1" ]script.sh ""script.sh$@$*$?${PIPESTATUS[@]}$$$BASHPID