Bash的\$@和\$*
深入理解 $@ 与 Bash 参数处理
在 Bash 脚本编写中,$@ 和 $* 都用于处理 脚本参数(Positional Parameters),但它们的行为有所不同,理解它们的区别至关重要。本文将深入剖析它们的用法、适用场景,并对比 "$@" 和 "$*" 在不同场景下的表现。
1. $@ 和 $* 的基本概念
在 Bash 中:
$@代表所有参数,并保持参数的分割性。$*也代表所有参数,但会将它们合并成一个字符串。
假设我们编写了一个 Bash 脚本 test.sh,其内容如下:
#!/bin/bash
echo "Using \$*: $*"
echo "Using \$@: $@"
echo "Iterating over \$*:"
for arg in "$*"; do
echo "Arg: $arg"
done
echo "Iterating over \$@:"
for arg in "$@"; do
echo "Arg: $arg"
done
然后,我们执行:
bash test.sh "hello world" "foo bar" baz
让我们看看输出结果:
Using $*: hello world foo bar baz
Using $@: hello world foo bar baz
Iterating over $*:
Arg: hello world foo bar baz # 🚨 变成了一个整体!
Iterating over $@:
Arg: hello world
Arg: foo bar
Arg: baz # ✅ 正确地分割了参数
分析
"$*"将所有参数合并成一个字符串,结果"hello world foo bar baz"变成了一个整体。"$@"保持参数的分割性,所以for arg in "$@"仍然正确地遍历了"hello world"、"foo bar"和baz。
✅ 结论:"$@" 更安全,推荐使用!
2. "$@" 与 "${array[@]}"
Bash 也支持数组操作,数组变量可以使用 "$@" 类似的方式展开。
示例
#!/bin/bash
array=("hello world" "foo bar" "baz")
echo "Using \"\${array[*]}\": ${array[*]}"
echo "Using \"\${array[@]}\": ${array[@]}"
echo "Iterating with \"\${array[*]}\":"
for item in "${array[*]}"; do
echo "Item: $item"
done
echo "Iterating with \"\${array[@]}\":"
for item in "${array[@]}"; do
echo "Item: $item"
done
执行
Using "${array[*]}": hello world foo bar baz
Using "${array[@]}": hello world foo bar baz
Iterating with "${array[*]}":
Item: hello world foo bar baz # 🚨 变成了一个整体!
Iterating with "${array[@]}":
Item: hello world
Item: foo bar
Item: baz # ✅ 正确保持分割
总结
| 语法 | 作用 | 适用场景 |
|---|---|---|
"$*" |
把所有参数合并成一个字符串 | 不推荐,可能导致错误 |
"$@" |
逐个传递参数(不会丢失空格) | 推荐,适用于函数参数传递 |
"${array[*]}" |
把整个数组合并成一个字符串 | 不推荐,容易丢失原始分割 |
"${array[@]}" |
保持数组元素完整 | 推荐,适用于数组遍历 |
3. "$@" 在函数参数传递中的作用
在 Bash 函数中,"$@" 是最安全的方式来传递参数,否则可能会导致参数解析错误。例如:
错误示例(使用 "$*")
my_function() {
echo "Arguments:"
for arg in "$*"; do
echo "$arg"
done
}
my_function "hello world" "foo bar"
输出
Arguments:
hello world foo bar # 🚨 参数被错误合并!
"$*" 导致 "hello world" 和 "foo bar" 变成一个整体,这是错误的。
正确示例(使用 "$@")
my_function() {
echo "Arguments:"
for arg in "$@"; do
echo "$arg"
done
}
my_function "hello world" "foo bar"
输出
Arguments:
hello world
foo bar # ✅ 参数保持完整!
✅ 结论:在函数参数传递中,永远使用 "$@"!
4. "$@" 在 Git Hook 及 Shell Wrappers 中的应用
在 Git Hook 或 Shell Wrappers(封装 Git 命令的脚本)中,我们通常希望 将所有用户传入的参数原样传递给 git 命令。如果不小心使用了 "$*",可能会导致命令执行失败。例如:
错误示例(使用 "$*")
git() {
command git "$*"
}
git commit -m "Fix bug"
这会被解析为:
git "commit -m Fix bug" # 🚨 错误!
Git 可能会报错,因为 commit -m "Fix bug" 变成了一个整体字符串。
正确示例(使用 "$@")
git() {
command git "$@"
}
git commit -m "Fix bug"
这会正确解析为:
git commit -m "Fix bug" # ✅ 正确!
✅ 结论:在 Shell Wrappers 中,始终使用 "$@" 以确保参数传递正确!
5. 结论
| 语法 | 作用 | 适用场景 | 推荐指数 |
|---|---|---|---|
"$*" |
把所有参数合并成一个字符串 | 🚨 不推荐,容易导致参数解析错误 | ⭐ |
"$@" |
逐个传递参数,保持原始分割 | ✅ 推荐,适用于函数参数传递 | ⭐⭐⭐⭐⭐ |
"${array[*]}" |
把整个数组合并成一个字符串 | 🚨 不推荐,容易导致数据丢失 | ⭐ |
"${array[@]}" |
逐个传递数组元素,保持原始分割 | ✅ 推荐,适用于数组遍历 | ⭐⭐⭐⭐⭐ |
🚀 最佳实践
- 在 函数参数传递 和 Shell Wrappers 中,始终使用
"$@"。 - 在 数组展开 时,使用
"${array[@]}"以保持数据完整。 - 避免 使用
"$*"和"${array[*]}",除非你明确希望合并所有参数或数组元素为单个字符串。
📌 牢记这点,你的 Bash 脚本会更健壮、更安全!

浙公网安备 33010602011771号