位置参数与内部参数变量

一、位置参数(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的PID1234当前进程ID
$!后台最后进程PID1235最后放入后台的进程
$?上命令退出码0(成功)判断上条命令是否成功
$-当前Shell选项himBHShell的选项标志
$_上命令最后一个参数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 00表示成功
默认值${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 的不同来组合值,而 $@ 则会将值用” “来组合值!推荐使用 $@, 而不是$*

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注