一、位置参数(Positional Parameters)
1.1 什么是位置参数?
位置参数是脚本或函数接收命令行传入的参数,通过 $0, $1, $2… 访问。
1.2 基本用法
#!/bin/bash
# 脚本名: test.sh
echo "脚本名: $0" # 脚本本身
echo "第一个参数: $1" # 第一个参数
echo "第二个参数: $2" # 第二个参数
echo "第三个参数: $3" # 第三个参数
echo "第十个参数: ${10}" # 10以上要用{}
# 执行
./test.sh a b c d
# 输出
脚本名: ./test.sh
第一个参数: a
第二个参数: b
第三个参数: c
第十个参数: # 没有第10个,为空
二、内部参数变量(Special Parameters)
| 变量 | 含义 | 示例 | 说明 |
|---|---|---|---|
$0 | 脚本名/函数名 | ./script.sh | 当前脚本文件名 |
$1 – $9 | 第1-9个参数 | $1 是第一个参数 | 直接使用 |
${10} | 第10个及以上参数 | ${10} | 10以上必须用{} |
$# | 参数个数 | 3 | 参数总数 |
$@ | 所有参数(独立) | "$1" "$2" "$3" | 每个参数单独加引号 |
$* | 所有参数(整体) | "$1 $2 $3" | 所有参数作为一个字符串 |
$$ | 当前Shell的PID | 1234 | 当前进程ID |
$! | 后台最后进程PID | 1235 | 最后放入后台的进程 |
$? | 上命令退出码 | 0(成功) | 判断上条命令是否成功 |
$- | 当前Shell选项 | himBH | Shell的选项标志 |
$_ | 上命令最后一个参数 | file.txt | 快速复用 |

三、详细示例
3.1 $# – 参数个数
#!/bin/bash
echo "参数个数: $#"
if [ $# -eq 0 ]; then
echo "没有传参数"
fi
# 执行
./test.sh a b c
# 输出: 参数个数: 3
3.2 $@ vs $* 关键区别
#!/bin/bash
# 演示 $@ 和 $* 的区别
echo "=== 使用 \$@ ==="
for arg in "$@"; do
echo "参数: $arg"
done
echo "=== 使用 \$* ==="
for arg in "$*"; do
echo "参数: $arg"
done
# 执行
./test.sh "hello world" a b
# 输出:
=== 使用 $@ ===
参数: hello world # 保持原样,一个参数
参数: a
参数: b
=== 使用 $* ===
参数: hello world a b # 所有参数合并成一个字符串
3.3 $? – 检查命令是否成功
#!/bin/bash
ls /etc/passwd
if [ $? -eq 0 ]; then
echo "文件存在"
else
echo "文件不存在"
fi
# 常用写法
if ls /etc/passwd >/dev/null 2>&1; then
echo "文件存在"
fi
3.4 $$ 和 $! – 进程ID
#!/bin/bash
echo "当前脚本PID: $$"
sleep 10 &
echo "后台进程PID: $!"
# 输出
当前脚本PID: 1234
后台进程PID: 1235
3.5 $_ – 上一个命令的最后一个参数
# 快速复用
mkdir /tmp/test
cd $_ # 等于 cd /tmp/test
# 另一个例子
ls -la /etc/passwd
echo $_ # 输出 /etc/passwd
四、参数处理技巧
4.1 遍历所有参数
#!/bin/bash
# 方法1: 使用 $@
for arg in "$@"; do
echo "处理: $arg"
done
# 方法2: 使用索引
for ((i=1; i<=$#; i++)); do
echo "第 $i 个参数: ${!i}" # 间接引用
done
4.2 参数默认值
#!/bin/bash
# 如果参数不存在,使用默认值
name=${1:-"匿名用户"}
age=${2:-18}
echo "姓名: $name"
echo "年龄: $age"
# 执行
./test.sh "张三" 25
# 姓名: 张三
# 年龄: 25
./test.sh
# 姓名: 匿名用户
# 年龄: 18
4.3 参数个数检查
#!/bin/bash
if [ $# -lt 2 ]; then
echo "用法: $0 <参数1> <参数2>"
exit 1
fi
4.4 shift – 参数左移
#!/bin/bash
echo "所有参数: $@"
shift 2 # 丢弃前2个参数
echo "shift后: $@"
# 执行
./test.sh a b c d e
# 输出:
所有参数: a b c d e
shift后: c d e
五、函数中的位置参数
#!/bin/bash
my_function() {
echo "函数名: $0" # 还是脚本名,不是函数名
echo "函数第一个参数: $1"
echo "函数第二个参数: $2"
echo "函数参数个数: $#"
}
echo "脚本参数: $@"
my_function x y z
# 执行
./test.sh 1 2 3
# 输出:
脚本参数: 1 2 3
函数名: ./test.sh
函数第一个参数: x
函数第二个参数: y
函数参数个数: 3
六、完整示例脚本
#!/bin/bash
# 文件名: params_demo.sh
echo "========== 位置参数 =========="
echo "脚本名: \$0 = $0"
echo "第一个参数: \$1 = $1"
echo "第二个参数: \$2 = $2"
echo "第三个参数: \$3 = $3"
echo -e "\n========== 内部参数 =========="
echo "参数个数: \$# = $#"
echo "所有参数(独立): \$@ = $@"
echo "所有参数(整体): \$* = $*"
echo "当前PID: \$$ = $$"
echo "上命令状态: \$? = $?"
echo -e "\n========== 遍历参数 =========="
echo "使用 \$@ 遍历:"
count=1
for arg in "$@"; do
echo " 参数 $count: $arg"
((count++))
done
echo -e "\n========== 参数默认值 =========="
name=${1:-"默认用户"}
echo "处理后的名字: $name"
# 执行示例
# ./params_demo.sh hello world "foo bar"
七、常用技巧速查
| 需求 | 写法 | 说明 |
|---|---|---|
| 获取所有参数 | "$@" | 推荐,保持参数原样 |
| 参数个数 | $# | 判断传了多少参数 |
| 检查上命令 | $? -eq 0 | 0表示成功 |
| 默认值 | ${1:-默认} | 参数为空时用默认 |
| 必须传参 | ${1:?错误信息} | 没传参就报错 |
| 跳过参数 | shift n | 丢弃前n个参数 |
| 最后一个参数 | $_ | 复用上命令参数 |
| 脚本PID | $$ | 临时文件用 |
核心记忆
| 变量 | 一句话记法 |
|---|---|
| $0 | 脚本自己 |
| $1-$9 | 第1-9个参数 |
| $# | 参数有几个 |
| $@ | 所有参数(各自独立) |
| $* | 所有参数(合成一个) |
| $? | 上条命令成功吗 |
| $$ | 我是谁(PID) |
| $! | 后台进程是谁 |
IFS变量
Shell 脚本中有个变量叫 IFS(Internal Field Seprator) ,内部域分隔符,IFS的默认值为:空白(包括:空格,tab, 和新行)
$ echo $IFS
$ echo “$IFS” | od -b
0000000 040 011 012 012
0000004
直接输出IFS是看不到的,把它转化为八进制就可以看到了,”040″是空格,”011″是Tab,”012″是换行符”\n” 。最后一个012是因为echo默认是会换行的。
$* 和 $@ 的差别举例:
总结:$* 会根据 IFS 的不同来组合值,而 $@ 则会将值用” “来组合值!推荐使用 $@, 而不是$*
发表回复