在许多SO问题和bash教程中,我看到我可以通过两种方式访问bash脚本中的命令行参数:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

结果是:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

$*和$@有什么区别? 什么时候应该使用前者,什么时候应该使用后者?


$@与$*相同,但每个参数都是一个带引号的字符串,也就是说,参数被完整地传递,没有解释或展开。这意味着,除其他外,参数列表中的每个参数都被视为一个单独的单词。

当然,“$@”应该加引号。

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST


$*

展开到位置参数,从1开始。当 展开发生在双引号内,它展开为单个单词 的第一个字符分隔每个参数的值 IFS特殊变量。也就是说,“$*”相当于“$1c$2c…”, 其中c是IFS变量值的第一个字符。如果 不设置IFS,参数间以空格分隔。如果IFS为空, 参数的连接没有中间分隔符。

$@

Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).

来源:Bash man


当特殊参数被引用时,会出现差异。让我来说明一下它们的区别:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

关于引用重要性的另一个例子:注意在“arg”和数字之间有2个空格,但如果我没有引用$word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

在bash中,“$@”是迭代的“默认”列表:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

一个来自Bash Hackers Wiki的非常方便的概览表:

Syntax Effective result
$* $1 $2 $3 … ${N}
$@ $1 $2 $3 … ${N}
"$*" "$1c$2c$3c…c${N}"
"$@" "$1" "$2" "$3" … "${N}"

其中第三行中的c是$IFS的第一个字符,输入字段分隔符,一个shell变量。

如果要存储参数,则将它们加载到数组变量中。


这个例子让我们在使用“at”和“asterix”时突出它们之间的区别。 我声明了两个数组水果和蔬菜

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

请看上面代码的结果:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion