shell获得parameter expansion, command substitution,arithmetic expansion的结果,如果扩展不发生在双引号内,执行word splitting。
shell使用IFS变量的值,作为分隔符来切割扩展结果。如果IFS是unset的,或者默认情况下,分隔符是:<space><tab><newline>。
扩展结果前面的和后面的这些分隔符被去掉忽略。中间的任何IFS序列,都用来切割字符。
如果IFS不是默认值,前面的和后面的IFS空白仍然会被去掉。中间的非IFS空白的IFS字符结合IFS空白字符一起来切割扩展结果,也就说IFS空白字符总是分隔符。
如果IFS是nul,那么不执行word splitting。
$ a="1 2"
$ printarg $a
args: 2
0(1): 1
1(1): 2
$ printarg "$a"
args: 1
0(3): 1 sp 2
可以看到,没有使用双引号,那么$a,执行了word splitting,扩展成了两个参数。使用引号,则没有执行word splitting。
显式的null argument(""和''),作为空字符串参数传递给命令。
unquoted implicit null argument,如果扩展的结果是空,那么被移除。如果使用了双引号,那么作为一个空字符串参数传递给命令。
$ a=""
$ printarg $a
$ printarg "$a"
args: 1
0(0):
[[ expression ]]
name=[value],注意除了$@
here strings
[n] <<< word
$*
从位置1开始,扩展positional parameters。
如果扩展不在双引号内:每个positional parameter扩展成一个separate word。这执行扩展的上下文,这些words还会进一步执行word splitting和pathname expansion。
如果扩展在双引号内:它扩展成一个单个的word,每个参数用IFS特殊变量的第一个字母分开,如果IFS是unset的,那么使用space分开。
$@
从位置1开始,扩展positional parameters。
在执行word splitting的上下文,每个位置参数扩展成separate word,如果没有双引号,这些words会进一步进行word splitting。
在不执行word splitting的上下文,扩展成单个word,每个位置参数使用空格分开。当使用双引号,那么每个位置参数扩展成separate word。
执行word splitting上下文的例子:
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 26 27 28 29 30 | $ cat test .sh run_cmd () { echo ++++++++++++++++ while [ $ # -ge 1 ] ; do echo $1 shift done } run_cmd $* run_cmd "$*" run_cmd $@ run_cmd "$@" $ . /test .sh "1 2" 3 ++++++++++++++++ 1 2 3 ++++++++++++++++ 1 2 3 ++++++++++++++++ 1 2 3 ++++++++++++++++ 1 2 3 |
解释:
$*,先扩展成"1 2" 3,然后"1 2",执行word splitting,最终扩展成:"1" "2" "3"
"$*",将"1 2"和3,使用IFS的第一个字符,即空格拼接成单个word,结果:"1 2 3"
$@,每个位置参数扩展成单个word,即:"1 2" 3,然后没有引号则执行word splitting。所以
$@扩展成"1" "2" "3","$@"扩展成了"1 2","3"。
不支持word splitting的上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $ cat test .sh a=$* b= "$*" c=$@ d= "$@" printarg "$a" printarg "$b" printarg "$c" printarg "$d" $ . /test .sh "1 2" 3 args: 1 0(6): 1 sp sp 2 sp 3 args: 1 0(6): 1 sp sp 2 sp 3 args: 1 0(6): 1 sp sp 2 sp 3 args: 1 0(6): 1 sp sp 2 sp 3 |
结果都一样。