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

75

在我看来,它们都存储了所有的命令行参数。

那么这两者之间有区别吗?

2个回答

115

区别微妙;"$*"将创建一个由$IFS变量分隔的参数,而"$@"会扩展为单独的参数。例如,请考虑:

for i in "$@"; do echo "@ '$i'"; done
for i in "$*"; do echo "* '$i'"; done

在使用多个参数运行时:

./testvar foo bar baz 'long arg'
@ 'foo'
@ 'bar'
@ 'baz'
@ 'long arg'
* 'foo bar baz long arg'

更多细节请参考:

http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters

$*

将位置参数展开,从一开始。当在双引号中进行扩展时,它会展开为一个单词,其中每个参数的值由IFS特殊变量的第一个字符分隔。也就是说,"$*" 等同于 "$1c$2c...",其中 c 是 IFS 变量值的第一个字符。如果未设置 IFS,则参数由空格分隔。如果 IFS 为空,则参数连接而成而不使用分隔符。

$@

将位置参数展开,从一开始。当在双引号中进行扩展时,每个参数都会扩展为一个单独的单词。也就是说,"$@" 等同于 "$1" "$2" .... 如果双引号扩展出现在一个单词中,则第一个参数的扩展与原始单词的前部分连接,最后一个参数的扩展与原始单词的后部分连接。 当没有位置参数时,"$@"$@ 扩展为空(即它们被删除)。


6
如果 $@ 和 $* 没有被放在双引号("")中,它们的扩展行为看起来是相同的。 - 爱国者
@爱国者 当未引用时,行为是不同的。请参见 https://dev59.com/x2ct5IYBdhLWcg3wI6J6#12316565 获取代码示例。 - Trismegistos

69

我个人认为一个关键的区别在于"$@"保留了原始参数的数量。这是唯一一个能够做到这一点的形式。

例如,如果文件 my_script 包含:

#!/bin/bash

main()
{
   echo 'MAIN sees ' $# ' args'
}

main $*
main $@

main "$*"
main "$@"

### end ###

我这样运行它:

my_script 'a b c' d e
我将得到以下输出:
MAIN sees  5  args
MAIN sees  5  args
MAIN sees  1  args
MAIN sees  3  args

1
哇,这个答案真的很详细!谢谢。 - erik
1
这是一个很好的说明方式,就像参数的数量一样。 - glenn jackman
但是为什么在这里使用$*和$@周围的括号会有所不同呢? - Totem
2
@Totem 我假设你说的是“圆括号”,但是实际上你是想说双引号。"$" 和 $ 的区别在于,用双引号会将 $* 的扩展作为单个字符串处理,而没有引号则允许将 $* 的各个部分视为单独的项。这是双引号的一般含义;此行为不特定于 $* 和 $@。另外,单引号和双引号之间的区别在于,在双引号中执行替换(如 $* 的扩展),但在单引号中不执行替换。('$*' 的结果只是 $*,即两个字符的文字值。) - Art Swri
@ArtSwri 非常感谢您的回答。我确实是指双引号。 - Totem

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