Shell Command Substitution – Unexpected Behaviour

shell

Given the shell script test.sh

for var in "$@"
do
    echo "$var"
done

and the invocation sh test.sh $(echo '"hello " "hi and bye"')

I would expect the output

hello
hi and bye

but instead get:

"hello
"
"hi
and
bye"

If I change to sh test.sh $(echo "hello " "hi and bye")

then I get

hello
hi
and
bye

Neither of these behaviours are desired, how can I get the desired behaviour?

What I want to understand is why sh test.sh $(echo "hello " "hi and bye") and sh test.sh "hello " "hi and bye" are not equivalent?

Best Answer

Your command substitution will generate a string.

In the case of

$(echo '"hello " "hi and bye"')

this string will be "hello " "hi and bye".

The string is then undergoing word splitting (and filename globbing, but it doesn't affect this example). The word splitting happen on every character that is the same as one of the characters in $IFS (by default, spaces, tabs and newlines).

The words generated by the default value of IFS would be "hello, ", "hi, and, and bye".

These are then given as separate arguments to your script.

In your second command, the command substitution is

$(echo "hello " "hi and bye")

This generates the string hello hi and bye and the word splitting would result in the four words hello, hi, and, and bye.

In your last example, you use the two arguments hello and hi and bye directly with your script. These won't undergo word splitting because they are quoted.

Related Question