Search code examples
bashshellechocdcommand-substitution

Why isn't a semicolon in command substitution output treated identical to one in the original code?


In my understanding of command substitution this should work, but it doesn't, can you explain me why and how to do something like this.


Why does this work:

cd ..; echo 123            # output is "123", after changing directories

...when this doesn't:

cd $(echo "..; echo 123")  # error message is "cd: too many arguments"

Solution

  • Command substitution results (like expansion of variables) do not go through all parsing phases; they only go through word-splitting[1] and glob expansion[2], and even those happen only when the expansion itself is unquoted.

    That means that your result is identical to:

    cd "..;" "echo" "123"
    

    ...the semicolon is treated as literal text to be passed to the cd command, not shell syntax.

    This is a feature, not a bug: If command substitution results were parsed as syntax, writing secure shell scripts handling untrusted data would be basically impossible.


    [1] dividing the results into "words" on characters in IFS -- or, by default, whitespace.
    [2] looking at whether each resulting word can be treated as a filename-matching pattern, and, if so, matching them against the local filesystem.