When IFS has its default value and an array is printed without quotes, the interpreted value doesn't have quotes, but when IFS doesn't have a space it it, it does.
Using an echo web server and curl to demonstrate why this makes a difference:
bash-5.2$ echo $BASH_VERSION
+ echo '5.2.21(1)-release'
5.2.21(1)-release
bash-5.2$ declare -a testit=([0]="-H" [1]="foo: bar")
+ testit=(['0']='-H' ['1']='foo: bar')
+ declare -a testit
bash-5.2$ declare -p testit
+ declare -p testit
declare -a testit=([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 ${testit[@]}
+ echo -H foo: bar
-H foo: bar
bash-5.2$ curl [::1] ${testit[@]}
+ 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 "${testit[@]}"
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] "${testit[@]}"
+ 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 ${testit[@]}
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] ${testit[@]}
+ curl '[::1]' -H 'foo: bar'
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
foo: bar
bash-5.2$ echo "${testit[@]}"
+ echo -H 'foo: bar'
-H foo: bar
bash-5.2$ curl [::1] "${testit[@]}"
+ curl '[::1]' -H 'foo: bar'
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.5.0
Accept: */*
foo: bar
Why does the removal of the space from IFS (regardless of where you put the space, and regardless of whether you replace the space with another character; underscore, for example) cause this different behavior? The only value of IFS on output is the first character, and it doesn't matter where the space is to cause the unexpected behavior.
IFS
is used to split the result of a parameter expansion, per Word Splitting in the manual:
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.
When IFS
contains a space, the unquoted expansion foo: bar
gets split into the two words foo:
and bar
. When you remove the space from IFS
this splitting does not occur, so the debug output displays 'foo: bar'
in quotes to indicate that this is a single word on the command line and not two words like the space might otherwise indicate. You would also get the quotes in the debug output if IFS
contains a space but you quote the variable expansion to disable word splitting.
user@host$ var='foo: bar'
user@host$ set -x
user@host$ echo $var
+ echo foo: bar
foo: bar
user@host$ echo "$var"
+ echo 'foo: bar'
foo: bar
user@host$ declare -p IFS
+ declare -p IFS
declare -- IFS="
"