@anishsane correctly answers the topic question (that ls
is doing the wrapping and ways to remove them) and covers the quoting issue as well but the quoting issue is responsible for the line count difference and not ls
.
The issue here is entirely one of quoting and how command lines, echo, and command substitution all work.
The output from "$(ls ...)"
is a single string with embedded newlines protected from the shell via the quotes. Hand that value to echo
and echo
spits it back out literally (with the newlines).
The output from $(ls ...)
is a string that is unprotected from the shell and thus undergoes word splitting and whitespace normalization. Command substitution cannot terminate your command line early (you wouldn't want echo $(ls -1)
in a directory with two files to run echo first_file; second_file
would you?) the newlines are left as word separators between the arguments to echo
. The shell then word splits the result on whitespace (including newlines) and gives echo a list of arguments at which point echo
happily executes echo first_file second_file ...
which, as you can guess, only outputs a single line of output.
Try this to see what I mean:
$ c() {
printf 'argc: %s\n' "$#";
printf 'argv: %s\n' "$@"
}
$ ls *
a.sh b.sh temp
$ ls -1dmb *
a.sh, b.sh, temp
$ c "$(ls -1dmb *)"
argc: 1
argv: a.sh, b.sh, temp
$ c $(ls -1dmb *)
argc: 3
argv: a.sh,
argv: b.sh,
argv: temp