问题
Echoing without quotes... 1 line. Fine.
$ echo $(ls -1dmb /bin/*) > test
$ wc -l test
1 test
Echoing with quotes... 396 lines. Bad.
$ echo "$(ls -1dmb /bin/*)" > test
$ wc -l test
396 test
The problem comes when using echo for writing a file and expanding a long variable.
Why does this happen? How to fix it?
回答1:
ls
is detecting that your stdout
is not a terminal.
check the output of ls -1dmb /bin/* | cat
vs ls -1dmb /bin/*
. It's ls
, who is splitting the output.
Similarly, for ls --color=auto
case, color
option is used, based on whether the stdout is terminal or not.
When quotes are used, echo
is provided with a single arguments, which has embedded newlines, spaces, which are echoed as-is to file.
When quotes are not used, echo
is provided multiple arguments, which are split by the IFS. Thus echo prints all of them in a single line.
But, don't skip these quotes...
How to fix it:
I think, the splitting always occurs at the end of some file name & never in between a filename. So one of these 2 options may work for you:
ls -1dmb /bin/* | tr '\n' ' ' >test
ls -1dmb /bin/* | tr -d '\n' >test
回答2:
@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
来源:https://stackoverflow.com/questions/25685054/why-echo-splits-long-lines-in-80-chars-when-printing-within-quotes-and-how-to