访问bash命令行args $ @ vs $ *

Accessing bash command line args $@ vs $*

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

1
2
3
4
5
$ ~ >cat testargs.sh
#!/bin/bash

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

结果是:

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ 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"和数字之间有两个空格,但是如果我没有报价$word:

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

在bash中,"$@"是要迭代的"默认"列表:

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


bash hacker wiki提供了一个方便的概述表:

$* versus $@ table

其中第三行中的c$IFS的第一个字符,内部字段分隔符;环境变量。

如果参数要存储在脚本变量中,并且参数应该包含空格,那么我衷心建议使用"$*"技巧,并将内部字段分隔符$IFS设置为tab。


$*

Expands to the positional parameters, starting from one. When the
expansion occurs within double quotes, it expands to a single word
with the value of each parameter separated by the first character of
the IFS special variable. That is,"$*" is equivalent to"$1c$2c...",
where c is the first character of the value of the IFS variable. If
IFS is unset, the parameters are separated by spaces. If IFS is null,
the parameters are joined without intervening separators.

$@

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).

资料来源:巴什曼


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

当然,应该引用"$@"。

http://tldp.org/ldp/abs/html/internalvariables.html arglist


这个例子让我们在使用"at"和"asterix"时强调它们之间的区别。我宣布了两个阵列"水果"和"蔬菜"

1
2
3
4
5
6
7
8
9
10
11
12
fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

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

以上代码见以下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
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