$ @变量似乎保持引用它的参数,例如:
$ function foo { for i in "$@"; do echo $i; done }
$ foo herp "hello world" derp
herp
hello world
derp
Run Code Online (Sandbox Code Playgroud)
我也知道bash数组,工作方式相同:
$ a=(herp "hello world" derp)
$ for i in "${a[@]}"; do echo $i; done
herp
hello world
derp
Run Code Online (Sandbox Code Playgroud)
这样的变量究竟发生了什么?特别是当我在报价中添加一些内容,比如"duck $ {a [@]} goose".如果它的空间不分隔是什么呢?
Rob*_*vis 11
通常,Bash中的双引号表示"将引号之间的所有内容都设为一个单词,即使它中包含分隔符." 但正如你所注意到的那样,$@当它在双引号内时表现不同.这实际上是一个可以追溯到Bash的前身Bourne shell的解析hack,这种特殊行为仅适用于这个特定的变量.
没有这个hack(我使用这个术语,因为它从语言的角度来看似乎不一致,虽然它非常有用),但是shell脚本很难将其参数数组传递给需要相同参数的其他命令.其中一些参数可能在它们中有空格,但是如果没有shell将它们作为一个大字汇集在一起或者重新分析列表并拆分具有空格的参数,它将如何将它们传递给另一个命令?
嗯,你可以传递参数数组,和Bourne shell真的只有一个阵列,通过代表$*或$@,其元素的数目是$#和其元素$1,$2等等,即所谓的位置参数.
一个例子.假设在当前目录下三个文件,命名aaa,bbb和cc c(第三个文件的名称中有空格).您可以将数组初始化(即,您可以设置位置参数)作为当前目录中文件的名称,如下所示:
set -- *
Run Code Online (Sandbox Code Playgroud)
现在,位置参数数组包含文件的名称.$#,元素的数量,是三:
$ echo $#
3
Run Code Online (Sandbox Code Playgroud)
我们可以通过几种不同的方式迭代位置参数.
1)我们可以使用$*:
$ for file in $*; do
> echo "$file"
> done
Run Code Online (Sandbox Code Playgroud)
但是重新分隔空格上的参数并调用echo四次:
aaa
bbb
cc
c
Run Code Online (Sandbox Code Playgroud)
2)或者我们可以在上面加上引号$*:
$ for file in "$*"; do
> echo "$file"
> done
Run Code Online (Sandbox Code Playgroud)
但是它将整个数组分组为一个参数并且只调用一次echo:
aaa bbb cc c
Run Code Online (Sandbox Code Playgroud)
3)或者我们可以使用$@哪个表示相同的数组但在双引号中表现不同:
$ for file in "$@"; do
> echo "$file"
> done
Run Code Online (Sandbox Code Playgroud)
会产生
aaa
bbb
cc c
Run Code Online (Sandbox Code Playgroud)
因为$ 1 ="aaa",$ 2 ="bbb",$ 3 ="cc c"并"$@"保持元素完好无损.如果你不引用引号$@,那么shell会变平并重新解析数组,echo会被调用四次,你会得到与裸露相同的东西$*.
这在shell脚本中特别有用,其中位置参数是传递给脚本的参数.要将这些相同的参数传递给其他命令 - 没有shell在空格上重新分割它们 - 请使用"$@".
# Truncate the files specified by the args
rm "$@"
touch "$@"
Run Code Online (Sandbox Code Playgroud)
在Bourne中,此行为仅适用于位置参数,因为它实际上是该语言支持的唯一数组.但是你可以在Bash中创建其他数组,你甚至可以使用特殊"${ARRAYNAME[@]}"语法将旧的解析hack应用于那些数组,其符号感觉几乎就像Bourne先生的眨眼:
$ declare -a myarray
$ myarray[0]=alpha
$ myarray[1]=bravo
$ myarray[2]="char lie"
$ for file in "${myarray[@]}"; do echo "$file"; done
alpha
bravo
char lie
Run Code Online (Sandbox Code Playgroud)
哦,你的最后一个例子,什么都要壳做的"pre $@ post",你有$@双引号内,但你有其他的东西在里面,太?最新版本的Bash保留数组,$@在第一个数组元素之前添加文本,并将文本追加$@到最后一个元素之后:
pre aaa
bb
cc c post
Run Code Online (Sandbox Code Playgroud)