Reputation: 1696
nkcoder@nkcoder:bash$ ls
doublebracket.sh for.sh if.sh quote.sh singlebracket.sh test.sh
nkcoder@nkcoder:bash$ ls | wc -l
6
nkcoder@nkcoder:bash$ echo $(ls)
doublebracket.sh for.sh if.sh quote.sh singlebracket.sh test.sh
nkcoder@nkcoder:bash$ echo $(ls) | wc -l
1
nkcoder@nkcoder:bash$ echo "$(ls)"
doublebracket.sh
for.sh
if.sh
quote.sh
singlebracket.sh
test.sh
nkcoder@nkcoder:bash$ echo "$(ls)" | wc -l
6
ls
is 6 lines, where is the newline ? I'm really confused, could anybody help to provide some explanation? Thanks a lot.
Upvotes: 0
Views: 89
Reputation: 295766
As I read it, there are multiple questions here:
ls | wc -l
report a different number of lines of output than that seen running ls
manually?ls
checks whether its stdout is a TTY -- the same check your own scripts can do with [[ -t 1 ]]
. If that test returns true, it modifies its output to be one line per file by default.
echo $(ls)
differ from echo "$(ls)"
?The output from expansions -- such as $(ls)
or $foo
is word-split if the expansion was not quoted.
Word-splitting happens on characters in the shell variable IFS
, or -- by default -- the space character, the tab, and the newline.
Results from that splitting are then substituted as individual arguments to the command being run. So:
$ rm -rf tmp.d && mkdir -p tmp.d && cd tmp.d && touch "hello cruel" world
$ echo $(ls)
...will first run ls
. Because output is not to a TTY, the output from ls
looks like this:
hello cruel
world
However, because the expansion was not inside quotes, the shell then splits that block into words. Because both the newline and the space character are in IFS by default, the fact that hello cruel
is a single filename is lost. Thus, we run:
$ echo "hello" "cruel" "world"
By contrast, if you run:
$ echo "$(ls)"
...then the shell doesn't string-split on whitespace, so it invokes:
$ echo 'hello cruel
world'
Mind you, if you really want to iterate over files, you shouldn't be using ls
at all. See Why you shouldn't parse the output of ls(1)
Upvotes: 1
Reputation: 1823
Double quotes will preserve the spaces and new lines of ls
command to echo
command and that is the reason when you are using double quotes you are getting actual count rather than using with out quotes.
# echo hai\
> bye
haibye
# echo "hai
> bye"
hai
bye
Upvotes: 0
Reputation: 6723
In bash, all unquoted arguments (including an argument generated by command substitution (`` or $())) is combined into a single line. Using quotes keeps the argument (the command substitution output) in its original form, so the newlines are preserved.
To see the difference, you can run:
function three_lines()
{
echo one; echo two; echo three
}
$ three_lines
one
two
three
$ echo `three_lines`
one two three
$ echo "`three_lines`"
one
two
three
Upvotes: 2