代码之家  ›  专栏  ›  技术社区  ›  Nayana Adassuriya

$*和$@

  •  29
  • Nayana Adassuriya  · 技术社区  · 10 年前

    谁能简单解释

    1. $*和$@之间有什么区别?
    2. 为什么与上述内容相同的内容有两个变量?
    4 回复  |  直到 10 年前
        1
  •  32
  •   Hari Menon    10 年前

    如果你不把 $* $@ 在引号中。但如果你把它们放在引号里(作为一种普遍的良好做法,你应该这样做),那么 $@ 将作为单独的参数传递参数,而 $* 将仅作为单个参数传递所有参数。

    接受这些脚本( foo.sh bar.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 $* => 巴/秒 得到 arg1 , arg2 arg3 作为单独的参数

    ./bar.sh $@ => 巴/秒 得到 arg1 , 参数2 参数3 作为单独的参数

    案例2:使用引号 $* $@ :

    ./bar.sh "$*" => 巴/秒 得到 arg1 arg2 arg3 作为单个参数

    ./bar.sh "$@" => 巴/秒 得到 arg1 , 参数2 参数3 作为单独的参数

    更重要的是, $* 也会忽略参数列表中的引号。例如,如果您提供 ./foo.sh arg1 "arg2 arg3" ,即使如此:

    ./bar.sh“$*” => 巴/秒 仍将收到 参数2 参数3 作为单独的参数!

    ./bar.sh“$@” =>将通过 arg2 arg3 作为单个参数(这是您通常想要的)。

    再次注意,只有当您将 $* $@ 在引号中。否则他们也会有同样的行为。

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

        2
  •  16
  •   Jonas Schäfer    10 年前

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

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

    #!/bin/bash
    rm $*
    

    test2.sh :

    #!/bin/bash
    rm "$*"
    

    test3.sh :

    #!/bin/bash
    rm $@
    

    test4.sh :

    #!/bin/bash
    rm "$@"
    

    (我正在使用 rm 此处而不是 echo ,因为使用 回响 ,看不出区别)

    我们使用以下命令行在一个否则为空的目录中调用它们:

    ./testX.sh "Hello World" Foo Bar
    

    对于 测试1.sh 测试3.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
    

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

    具有 测试2.sh ,我们得到:

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

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

    测试4.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的众多陷阱之一的一个很好的例子。

        3
  •  7
  •   l0b0    10 年前

    看看这个 here :

    $#    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
    
        4
  •  2
  •   jlliagre    1 年前

    引用时它们不同:

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

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

    这里只有第二种形式保留了参数计数。