当 IFS 有默认值并且打印的数组不带引号时,解释后的值没有引号,但当 IFS 没有空格时,它就会有。
使用 echo Web 服务器和curl 来演示为什么这会产生影响:
bash-5.2$ echo $BASH_VERSION
+ echo '5.2.21(1)-release'
5.2.21(1)-release
bash-5.2$ declare -a test=([0]="-H" [1]="foo: bar")
+ test=(['0']='-H' ['1']='foo: bar')
+ declare -a test
bash-5.2$ declare -p test
+ declare -p test
declare -a test=([0]="-H" [1]="foo: bar")
bash-5.2$ IFS=$' \t\n'
+ IFS='
'
bash-5.2$ declare -p IFS
+ declare -p IFS
declare -- IFS=$' \t\n'
bash-5.2$ echo ${test[@]}
+ echo -H foo: bar
-H foo: bar
bash-5.2$ curl [::1] ${test[@]}
+ curl '[::1]' -H foo: bar
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
curl: (6) Could not resolve host: bar
bash-5.2$ echo "${test[@]}"
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] "${test[@]}"
+ curl '[::1]' -H 'foo: bar'
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
foo: bar
bash-5.2$ IFS=$'_\t\n'
+ IFS='_
'
bash-5.2$ declare -p IFS
+ declare -p IFS
declare -- IFS=$'_\t\n'
bash-5.2$ echo ${test[@]}
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] ${test[@]}
+ curl '[::1]' -H 'foo: bar'
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
foo: bar
bash-5.2$ echo "${test[@]}"
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] "${test[@]}"
+ curl '[::1]' -H 'foo: bar'
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
foo: bar
为什么从 IFS 中删除空格(无论您将空格放在哪里,也无论您是否用其他字符替换空格;例如下划线)会导致这种不同的行为? output 上 IFS 的唯一值是第一个字符,无论空格在哪里都会导致意外行为。
IFS
用于分割参数扩展的结果,根据手册中的Word Splitting:
The shell scans the results of parameter expansion, command substitution,
and arithmetic expansion that did not occur within double quotes for word splitting.
The shell treats each character of $IFS as a delimiter, and splits
the results of the other expansions into words using these characters
as field terminators.
当
IFS
包含空格时,未加引号的扩展 foo: bar
会被拆分为两个单词 foo:
和 bar
。当您从 IFS
中删除空格时,不会发生这种拆分,因此调试输出显示 'foo: bar'
以指示这是命令行上的单个单词,而不是像空格可能指示的两个单词。