在Bash脚本中,$@和$*有什么区别?

22

以下有4个bash代码片段,我使用./script.sh a b c进行调用。

for arg in $@; do 
echo "$arg"
done   ## output "a\nb\nc"

for arg in "$@"; do
echo "$arg"
done  ## output "a\nb\nc" -- I don't know why

for arg in $*; do
echo "$arg"
done  ##    output "a\nb\nc"

for arg in "$*"; do
echo "$arg"
done    ## output "abc"

我不知道$@$*之间的确切区别,
我认为"$@""$*"应该是相同的,但它们并不相同。为什么呢?

3个回答

45
如果你有一个脚本foo.sh
asterisk "$*"
at-sign "$@"

并通过以下方式调用:

./foo.sh "a a" "b b" "c c"

它相当于:

asterisk "a a b b c c"
at-sign "a a" "b b" "c c"

没有引号时,它们是一样的:

asterisk $*
at-sign $@

将等价于:

asterisk "a" "a" "b" "b" "c" "c"
at-sign "a" "a" "b" "b" "c" "c"

6
举例说明比抽象描述更有帮助。 - Barmar
这个救了我很多时间,没有引号的话,我没有意识到bash会切分我的参数。 - faulty

9
$*和$@的区别是:
"$*"代表所有位置参数(作为单个单词)
"$@"代表所有位置参数(作为单独的字符串)
如果你将bash脚本中给定的三个命令行参数传递给C程序使用./my_c $@,
你会得到结果:ARG[1] == "par1" ARG[2] == "par2" ARG[3] == "par3"
如果你将bash脚本中给定的三个命令行参数传递给C程序使用./my_c $*,
你会得到结果:ARG[1] == "par1 par2 par3"

2
这在shell脚本中很重要:例如,脚本testargs.sh。
#! /bin/bash -p

echo $#

for i in $(seq 1 $#)
do
    echo "$i: ${!i}"
done

for val in "$@"; do
    echo "in quote @, $val"
done

for val in "$*"; do
    echo "in quote *, $val"
done

for val in $@; do
    echo "not in quote @, $val"
done

for val in $*; do
    echo "not in quote *, $val"
done

如果执行此脚本为/tmp/testargs.sh a b c 'd e',结果如下:
4
1: a
2: b
3: c
4: d e
in quote @, a
in quote @, b
in quote @, c
in quote @, d e
in quote *, a b c d e
not in quote @, a
not in quote @, b
not in quote @, c
not in quote @, d
not in quote @, e
not in quote *, a
not in quote *, b
not in quote *, c
not in quote *, d
not in quote *, e

因此,如果要保留参数数量,请始终使用"$@"或使用for i in $(seq 1 $#)循环迭代每个参数。不带引号,两者相同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接