`$#`, `$?`, `$@`, `$1`

在 Shell 脚本中,$#, $?, $@, $1 以及其他以 $ 开头的特殊变量是位置参数和特殊参数,它们提供了关于脚本执行环境、传递给脚本的参数以及上一个命令执行状态的重要信息。


核心特殊变量详解

变量 名称 含义
$0 脚本名称 表示当前执行的脚本或程序的名称(包括路径,如果调用时包含路径)。
$1, $2, ..., $9 位置参数 表示传递给脚本或函数的第1个、第2个、...、第9个命令行参数。
${10} 位置参数 (10+) 当参数超过9个时,必须用 {} 括起来,如 ${10}, ${11} 等。
$# 参数个数 表示传递给脚本或函数的位置参数的总数量
$@ 所有参数 (保留空格) 表示传递给脚本或函数的所有位置参数。当用双引号括起来时 ("$@"),它会将每个参数视为单独的、带引号的字符串,保留了参数中的空格和特殊字符。这是遍历参数的推荐方式。
$* 所有参数 (合并为一个) 也表示所有位置参数。当用双引号括起来时 ("$*"),它会将所有参数合并成一个单一的字符串,参数之间用第一个字符(通常是空格)分隔。
$$ 当前进程ID (PID) 表示当前正在运行的 Shell 脚本的进程ID。常用于创建唯一的临时文件名。
$! 最后一个后台进程ID 表示最近一个在后台运行的进程的进程ID。例如:command & 后,$! 会保存 command 的 PID。
$? 上一个命令的退出状态 表示上一个执行的命令或脚本的退出状态码
* 0 表示成功。
* 非零值(通常是 1-255)表示失败或有错误。
$- 当前 Shell 选项标志 显示当前 Shell 的启用选项(如 himBH)。
$_ 上一个参数 表示上一个命令的最后一个参数。在脚本中,它通常表示 $0(脚本名),但在交互式 Shell 中很有用。
$IFS 内部字段分隔符 (Internal Field Separator) 一个特殊的环境变量,定义了 Shell 如何分隔单词。默认是空格、制表符和换行符。

详细示例

假设你有一个脚本 myscript.sh,并用以下命令执行它:

./myscript.sh "Hello World" file.txt 123
变量 在此命令下的值 说明
$0 ./myscript.sh 脚本名称
$1 Hello World 第一个参数(带空格,因为用引号括起来了)
$2 file.txt 第二个参数
$3 123 第三个参数
$# 3 总共有3个参数
$@ "Hello World" "file.txt" "123" 所有参数,每个都保持原样(当用 "$@" 引用时)
$* "Hello World file.txt 123" 所有参数合并成一个字符串(当用 "$*" 引用时)
$$ 12345 假设脚本的 PID 是 12345
$? (取决于上一个命令) 例如,如果上一个 ls 命令成功,$? 就是 0
$! (取决于后台进程) 如果刚运行了 sleep 100 &$! 就是 sleep 进程的 PID

$@ vs $* 的关键区别 (用双引号时)

这是最容易混淆的地方:

#!/bin/bash
# 假设调用: script.sh "a b" c

echo "使用 \"\$@\":"
for arg in "$@"; do
  echo "[$arg]"
done
# 输出:
# [a b]  <- 作为一个整体
# [c]

echo "使用 \"\$*\":"
for arg in "$*"; do
  echo "[$arg]"
done
# 输出:
# [a b c] <- 所有参数合并成一个字符串

结论:在 for 循环或传递参数时,几乎总是应该使用 "$@",因为它能正确处理包含空格的参数。


其他重要的 $ 相关表达式

除了上述特殊变量,Shell 还支持强大的参数扩展 (Parameter Expansion),这些也以 $ 开头:

表达式 含义
${var} 基本变量引用,等同于 $var,但更安全,尤其在变量名后紧跟字符时。
${var:-default} 如果 var 未定义或为空,则使用 default
${var:=default} 如果 var 未定义或为空,则设置 vardefault 并使用它。
${var:+value} 如果 var 已定义且非空,则使用 value,否则为空。
${var:?message} 如果 var 未定义或为空,则打印 message 并退出脚本。
${#var} 返回变量 var字符串长度
${var#pattern} var 开头删除最短匹配 pattern 的部分。
${var##pattern} var 开头删除最长匹配 pattern 的部分。
${var%pattern} var 末尾删除最短匹配 pattern 的部分。
${var%%pattern} var 末尾删除最长匹配 pattern 的部分。
${var/pattern/replacement} var第一个匹配 pattern 的部分替换为 replacement
${var//pattern/replacement} var所有匹配 pattern 的部分替换为 replacement

总结

  • $1, $2, ...:获取具体的命令行参数。
  • $#:知道有多少个参数。
  • $@:安全地遍历或传递所有参数。
  • $?:检查上一个命令是否成功。
  • $$, $!:获取进程 ID。
  • 参数扩展:提供强大的字符串操作能力。

理解这些 $ 变量和表达式是编写健壮 Shell 脚本的基础。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容