Isso fornece uma única string como argumento para foo :
foo "${ENV_VAR_1} ${ENV_VAR_2}"
Como $1 não está entre aspas, o shell executa a divisão de palavras e, consequentemente, isso fornece três argumentos para bar :
bar $1
A divisão de palavras é feita em qualquer caractere IFS em S1 . A fonte original desses personagens não é considerada.
Exemplo mais simples
Vamos definir x como:
$ x="${ENV_VAR_1} ${ENV_VAR_2}"
Agora, vamos imprimir "$x" :
$ printf "%s\n" "$x"
1 2 3
Como você pode ver, "$x" é interpretado como um argumento. Por contraste, considere:
$ printf "%s\n" $x
1
2
3
Acima, a divisão de palavras é executada em $x , criando três argumentos.
As strings de shell não têm noção de histórico. A string x não tem registro de 2 3 sendo parte de uma sequência antes de x ser atribuído. A string x consiste apenas de 1 , espaço, 2 , espaço e 3 e a divisão de palavras opera nos espaços.
Alternativa: selecionando seu próprio IFS
Isso produz a saída que você deseja:
$ foo() ( IFS=@; bar $1; )
$ foo "${ENV_VAR_1}@${ENV_VAR_2}"
1 test 2 3
Em foo , definimos IFS para @ . Consequentemente, toda a divisão de palavras subsequente é executada usando @ como o separador de palavras. Portanto, ao chamar foo , colocamos um @ em qualquer local em que desejamos a divisão de palavras.