$*和$@有什么区别?

31

谁能简单解释一下

  1. $* 和 $@ 的区别是什么?
  2. 为什么同样的内容有两个变量?

https://unix.stackexchange.com/questions/129072/whats-the-difference-between-and - Channa
4个回答

36

如果不将 $* 或者 $@ 用引号括起来,它们之间没有差异。但是最好将它们放在引号中(作为一项通用的良好实践),这样 $@ 将会将您的参数作为单独的参数传递,而 $* 只会将所有参数作为单个参数传递。

以这些脚本(foo.shbar.sh)作为测试:

>> cat bar.sh
echo "Arg 1: $1"
echo "Arg 2: $2"
echo "Arg 3: $3"
echo

>> cat foo.sh
echo '$* without quotes:'
./bar.sh $*

echo '$@ without quotes:'
./bar.sh $@

echo '$* with quotes:'
./bar.sh "$*"

echo '$@ with quotes:'
./bar.sh "$@"

现在这个示例应该会让一切变得清晰明了:

>> ./foo.sh arg1 "arg21 arg22" arg3
$* without quotes:
Arg 1: arg1
Arg 2: arg21
Arg 3: arg22

$@ without quotes:
Arg 1: arg1
Arg 2: arg21
Arg 3: arg22

$* with quotes:
Arg 1: arg1 arg21 arg22 arg3
Arg 2:
Arg 3:

$@ with quotes:
Arg 1: arg1
Arg 2: arg21 arg22
Arg 3: arg3

"$@" 明显是我们通常所期望的行为。


更详细的描述:

情况1: $*$@ 没有用引号括起来:

它们的行为相同。

./bar.sh $* => bar.sh 会将 arg1, arg2arg3 作为单独的参数传递。

./bar.sh $@ => bar.sh 同样会将 arg1, arg2arg3 作为单独的参数传递。

情况2: $*$@ 被引号括起来:

./bar.sh "$*" => bar.sh 会将 arg1 arg2 arg3 作为单独的参数传递。

./bar.sh "$@" => bar.sh 会将 arg1, arg2arg3 作为单独的参数传递。

更重要的是,$* 在参数列表中忽略引号。例如,即使你提供了 ./foo.sh arg1 "arg2 arg3"

./bar.sh "$*" => bar.sh 仍会将 arg2arg3 作为单独的参数接收!

./bar.sh "$@" => 将 arg2 arg3 作为单个参数传递(这通常是我们想要的)。

请注意,只有当你将$*$@用引号括起来时才会出现这种差异。否则它们具有相同的行为。

官方文档:http://www.gnu.org/software/bash/manual/bash.html#Special-Parameters


2
看起来很复杂。你能简单地解释一下吗? - Nayana Adassuriya
1
好的...添加了解释 - Hari Menon

16

除了技术文件中所描述的差异外,最好使用一些示例来展示:

假设我们有四个shell脚本:test1.sh:

#!/bin/bash
rm $*

test2.sh:

#!/bin/bash
rm "$*"

test3.sh:

#!/bin/bash
rm $@

test4.sh:

#!/bin/bash
rm "$@"

这里我使用rm而不是echo,因为使用echo看不到差异。

我们在一个空目录中,用以下命令行调用它们:

./testX.sh "Hello World" Foo Bar

对于 test1.shtest3.sh,我们收到以下输出:

rm: cannot remove ‘Hello’: No such file or directory
rm: cannot remove ‘World’: No such file or directory
rm: cannot remove ‘Foo’: No such file or directory
rm: cannot remove ‘Bar’: No such file or directory

这意味着参数被作为整个字符串取出,用空格连接起来,然后重新解析为参数,并传递给命令。当转发参数到另一个命令时,这通常是没有帮助的。

使用test2.sh,我们会得到:

rm: cannot remove ‘Hello World Foo Bar’: No such file or directory

所以我们与test{1,3}.sh相同,但这次结果被作为一个参数传递。

test4.sh有一些新的东西:

rm: cannot remove ‘Hello World’: No such file or directory
rm: cannot remove ‘Foo’: No such file or directory
rm: cannot remove ‘Bar’: No such file or directory

这意味着参数的传递方式与它们被传递到脚本的方式相同。当将参数传递给其他命令时,这很有帮助。

虽然差别微妙,但当向需要在命令行的特定位置提供信息的命令传递参数并且空格参与其中时,它会使你遇到麻烦。这实际上是大多数Shell中许多陷阱的很好的例子。


9

看这个链接

$#    Stores the number of command-line arguments that 
      were passed to the shell program.
$?    Stores the exit value of the last command that was 
      executed.
$0    Stores the first word of the entered command (the 
      name of the shell program).
$*    Stores all the arguments that were entered on the
      command line ($1 $2 ...).
"$@"  Stores all the arguments that were entered
      on the command line, individually quoted ("$1" "$2" ...).

举个例子。
./command -yes -no /home/username
so now..
$# = 3
$* = -yes -no /home/username
$@ = ("-yes" "-no" "/home/username")
$0 = ./command
$1 = -yes
$2 = -no
$3 = /home/username

“individually quoted”的意思和用途是什么? - Nayana Adassuriya
@NayanaAdassuriya:引号用于命令组,例如 if(./command -yes -no "/home username"),则 $3="/home username",否则如果 (./command -yes -no /home username) 则 $3="/home",$4="username"。 - Dharmendrasinh Chudasama

2

当被引用时,它们是不同的:

$ set "a b" c d 
$ echo $#
3
$ set "$*"
$ echo $#
1

$ set "a b" c d 
$ echo $#
3
$ set "$@"
$ echo $#
3

只有第二个表单保留了参数数量。


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