To complement Colwin's effective answer with why the double quotes are needed:
If you pass an unquoted command substitution (e.g, `ls -l`
or, better, $(ls -l)
) or variable reference (e.g., $var
), the shell modifies the command output / variable value before passing the argument to the command.
This applies to all POSIX-compatible shells, not just bash
.
Specifically, the following so-called shell expansions
are performed:
word-splitting: the output is split into (potentially) multiple words by whitespace, including newlines (by default; the split characters can be set via $IFS
)
globbing (filename expansion): each resulting word is interpreted as a filename pattern and matched agains files in the current directory, and each matching filename becomes its own word, with all resulting words replacing the original word; by default, if nothing matches, the word is left as-is.
The resulting words are then passed as individual arguments to the target command.
By contrast, if you double-quote a command substitution ("$(ls -l)"
or variable reference ("$var"
), these expansions do NOT take place, and the output / value is passed as-is to the target command.
Therefore, in the case at hand:
- the shell removes all newlines from the output of
ls -l
- and then passes the resulting words individually, as multiple arguments to
echo
echo
simply concatenates multiple arguments you pass to it with spaces, which is why you're seeing the single-line output printed in your question.
In short: Due to not double-quoting `ls -l`
, echo `ls -l`
prints a space-separated, single-line list of the words contained in the output from ls -l
.