Shell中$*与$@的区别详解

这是一个Shell脚本中非常经典且重要的区别。

简单来说:

  • $* 将所有的参数视为一个单一的字符串
  • $@ 将所有的参数视为独立的、分开的字符串

这个区别只有在被双引号引用时("$*""$@")才会变得非常明显。如果不加引号,$*$@ 的行为是相同的。


详细解释与示例

我们通过一个简单的脚本 test.sh 来演示:

#!/bin/bash

echo "Testing \$* and \$@"

echo "--- Without double quotes ---"
echo "Using \$*:"
for arg in $*; do
  echo "[$arg]"
done

echo "Using \$@:"
for arg in $@; do
  echo "[$arg]"
done

echo "--- With double quotes ---"
echo "Using \"\$*\":"
for arg in "$*"; do
  echo "[$arg]"
done

echo "Using \"\$@\":"
for arg in "$@"; do
  echo "[$arg]"
done

运行这个脚本并传递几个参数:

bash test.sh one two "three four"

输出结果分析:

Testing $* and $@
--- Without double quotes ---
Using $*:
[one]
[two]
[three]
[four]
Using $@:
[one]
[two]
[three]
[four]

分析(未加引号):
当不加双引号时,$*$@ 的行为完全一样。它们都会经历“单词拆分”(Word Splitting)。参数 "three four" 作为一个带空格的字符串被传递进来,但 for 循环在遇到 $*$* 时,会按空格将其拆分成两个独立的单词 threefour这通常不是我们想要的行为

--- With double quotes ---
Using "$*":
[one two three four]
Using "$@":
[one]
[two]
[three four]

分析(加引号):
这才是关键区别所在!

  1. "$*"

    • 它将所有位置参数连接起来,形成一个单一的字符串
    • 各个参数之间用第一个字符(默认为空格)分隔。
    • 你可以通过改变特殊变量 IFS(Internal Field Separator)来改变这个分隔符。例如,如果设置了 IFS=,,那么 "$*" 的输出会变成 one,two,three four
    • 只有一个循环迭代,因为所有参数被合并成了一个字符串。
  2. "$@"

    • 它将每个位置参数都视为一个被引用的独立字符串
    • 这是最有用、最安全的用法。它保留了每个参数的原始边界。
    • 参数 onetwo"three four" 被完美地保留了。"three four" 中的空格没有被拆分,它被正确地当作一个参数处理。
    • 有三个循环迭代,对应我们传入的三个参数。

总结与使用建议

特性$*$@建议
不加引号参数会经历单词拆分和文件名扩展参数会经历单词拆分和文件名扩展避免使用,行为不可预测
加引号 "..."一个字符串:将所有参数合并为一个字符串参数列表:将每个参数作为独立的、被引用的字符串这是正确的用法
何时使用当你需要将所有参数作为一个整体处理时,例如,将它们全部打印在一行或用自定义分隔符连接它们。几乎总是使用这个。当你需要将参数原封不动地传递给另一个命令,或者需要循环处理每个参数时。优先使用 "$@"

黄金法则:

几乎在所有情况下,你都应该使用加引号的 "$@" 来访问脚本的位置参数。 这是保留参数原始含义和数量的最安全、最可靠的方法。

例如,编写一个包装脚本时,你需要将收到的所有参数都传递给另一个命令:

#!/bin/bash
# wrapper.sh

# 将收到的所有参数原封不动地传递给 `git`
# 使用 "$@" 是唯一正确的方法
git "$@"

运行 bash wrapper.sh commit -m "my message""$@" 能确保 -m"my message" 作为两个独立的参数传递给 git,而如果使用 "$*",整个命令会变成 git commit -m my message,这完全是错误的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值