在shell脚本中,$@是什么意思?

374

在 shell 脚本中,一个美元符号后面跟着一个 at 符号 (@) 是什么意思?

例如:

umbrella_corp_options $@
8个回答

422

$@ 是传递给脚本的所有参数。

例如,如果你调用 ./someScript.sh foo bar,那么 $@ 将等于 foo bar

如果你执行:

./someScript.sh foo bar

然后在 someScript.sh 文件内引用:

umbrella_corp_options "$@"

这将被传递给umbrella_corp_options,每个单独的参数都用双引号括起来,允许从调用者处获取带有空格参数并将其传递。


2
如果我运行 someScript.sh foo bar "boo far",那么 $@ 会包含什么? - trusktr
2
请查看此链接:http://teaching.idallen.com/dat2330/04f/notes/shell_variables.txt - Har
11
如果以双引号形式书写,$@ 就是一个特殊符号。此时它会将值放在引号里面变成一个列表,对于你的情况来说,"foo"、"bar" 和 "boo far" 这三个参数会被引号括起来,其中 trusktr 是其中一个参数的值。 - Alfe
5
尽管通常情况下是这样,但$@不一定来自于传递给脚本的参数...例如:set a b "x   y"; printf '(%s)' "$@"的输出结果为(a)(b)(x   y) - Peter.O
4
我更喜欢Alfe的答案,因为他提供了$@$*之间的主要区别。 - donleyp
2
小细节:有一个隐式参数 $0$@ 是从 $1 开始的所有参数。 - Roland

202

$@$*几乎相同,都表示“所有命令行参数”。它们经常用于通过简单地将所有参数传递给另一个程序(从而形成该其他程序的包装器)。

当您遇到带有空格的参数(例如),并将$@放在双引号中时,两种语法之间的区别就会显现出来:

wrappedProgram "$@"
# ^^^ this is correct and will hand over all arguments in the way
#     we received them, i. e. as several arguments, each of them
#     containing all the spaces and other uglinesses they have.
wrappedProgram "$*"
# ^^^ this will hand over exactly one argument, containing all
#     original arguments, separated by single spaces.
wrappedProgram $*
# ^^^ this will join all arguments by single spaces as well and
#     will then split the string as the shell does on the command
#     line, thus it will split an argument containing spaces into
#     several arguments.

示例:调用

wrapper "one two    three" four five "six seven"

将导致:

"$@": wrappedProgram "one two    three" four five "six seven"
"$*": wrappedProgram "one two    three four five six seven"
                             ^^^^ These spaces are part of the first
                                  argument and are not changed.
$*:   wrappedProgram one two three four five six seven

4
它们并不相同,而且手册已经清楚说明了使用IFS时$*的副作用——它不一定是空格。(如果它们是相同的,那么提供两者除了兼容性之外就没有任何意义了。) - jørgensen
11
不,它们并不是。而且我在两行之后就说了:“两者之间的区别......”为了使句子更简短、易读,读者必须在做出判断之前读多于一句的内容。:-/ - Alfe
3
Alfe,克里斯托弗插入那个词“几乎”真的起到了很大的作用,而没有牺牲任何简洁性或易读性。事实上,我点赞了这个答案(与被接受的答案相反),正是由于那种微妙的强调“差异”......之前才意识到这几乎是违背你的意愿! ;) - Sz.
我认为这个词对那些在读完第一句话后就做出裁决的人来说有很大的影响;-)而且这从来不是违背我的意愿。我真的很想为这些人写作。 - Alfe
@barlop 因为没有引号的 $@ 是没有用的。如果它出现了,通常只是一个错误,有引号的版本才是预期的。没有引号时,它与没有引号的 $* 相同(这是一致的,但是,正如我所说,无用的)。 - Alfe
显示剩余3条评论

67

以下是命令行参数的解释:

$@ = 将所有参数存储在字符串列表中
$* = 将所有参数存储为单个字符串
$# = 存储参数数量


由@iruvar提出的上述不准确之处已被修复。 - Mateen Ulhaq
2
在这个上下文中,“list”是什么? - Magnus
"$@" 实际上不是字符串列表,而是参数列表。 - Luis Lavaire.
但是,“list”是什么? - GameKyuubi
@GameKyuubi 你可以在这里了解更多关于列表(而不是数组)的内容:https://www.gnu.org/software/bash/manual/bash.html#Arrays - user16328828

18

在大多数情况下,纯粹的$@意味着“尽可能地伤害程序员”,因为在大多数情况下,它会导致单词分隔和参数中的空格和其他字符问题。

在(猜测)99%的情况下,需要将其用引号括起来:"$@"可以可靠地迭代参数。

for a in "$@"; do something_with "$a"; done

5
您的代码可以写成:for a; do something_with "$a"; done;-)。 - Alfe
1
@Alfe 我知道,我只是忘记了。把它想象成 for a in start_token "$@" end_token; do something_with "$a"; done 就好了 :-) - glglgl

17

含义。

简而言之,$@扩展为从调用者传递给一个函数脚本参数。它的含义是上下文相关的:在函数内部,它扩展为传递给该函数的参数。如果在脚本中使用(不在函数内),它会扩展为传递给该脚本的参数。

$ cat my-script
#! /bin/sh
echo "$@"

$ ./my-script "Hi!"
Hi!

$ put () { echo "$@"; }
$ put "Hi!"
Hi!

* 注意:单词分割。

Shell根据IFS环境变量的内容来分割标记。它的默认值是 \t\n,也就是空格、制表符和换行符。扩展"$@"可以给你一个传递参数的完美副本。但是扩展$@不一定如此。更具体地说,任何包含在IFS中出现的字符的参数都可能被分成两个或更多个参数,或者被截断。

因此,大多数情况下你需要使用的是"$@",而不是$@


13

来自手册:

@

扩展为从1开始的位置参数。当在双引号内扩展时,每个参数会扩展为一个单独的单词。也就是说,“$@”等同于“$1”“$2”...。如果双引号扩展出现在一个单词内部,则第一个参数的扩展与原始单词的起始部分连接,最后一个参数的扩展则与原始单词的最后一部分连接。当没有位置参数时,“$@”和“$*”不会扩展任何内容(即它们被删除)。


-1

$@ 基本上用于引用 shell 脚本的所有命令行参数。 $1,$2,$3 分别引用第一个、第二个和第三个命令行参数。


-2

它们通常用于将所有参数简单地传递给另一个程序

[root@node1 shell]# ./my-script hi 11 33 hi 11 33 [root@node1


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