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
的输出是6行,换行符在哪里? 我真的很困惑,有人可以帮忙提供一些解释吗?非常感谢。
答案 0 :(得分:2)
在bash中,所有不带引号的参数(包括由命令替换生成的参数(``或$()))组合成一行。使用引号使参数(命令替换输出)保持其原始形式,因此保留换行符。
要查看差异,您可以运行:
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
答案 1 :(得分:1)
在我阅读时,这里有多个问题:
ls | wc -l
报告的输出行数不同于手动运行ls
的输出行数? ls
检查其标准输出是否为TTY - 同样检查您自己的脚本可以对[[ -t 1 ]]
进行检查。如果该测试返回true,则默认情况下将其输出修改为每个文件一行。
echo $(ls)
与echo "$(ls)"
不同?如果未引用扩展,则扩展的输出(例如$(ls)
或$foo
word-split 。
分词发生在shell变量IFS
中的字符上,或者 - 默认情况下 - 空格字符,制表符和换行符。
然后将该拆分的结果替换为正在运行的命令的单个参数。所以:
$ rm -rf tmp.d && mkdir -p tmp.d && cd tmp.d && touch "hello cruel" world
$ echo $(ls)
...将首先运行ls
。因为输出不是TTY,ls
的输出如下所示:
hello cruel
world
但是,因为扩展不在引号内,所以shell会将该块拆分为单词。因为默认情况下换行符和空格字符都在IFS中,所以hello cruel
是单个文件名的事实将丢失。因此,我们运行:
$ echo "hello" "cruel" "world"
相比之下,如果你跑:
$ echo "$(ls)"
...然后shell不会在空格上进行字符串拆分,因此它会调用:
$ echo 'hello cruel
world'
请注意,如果您真的要迭代文件,则根本不应该使用ls
。见Why you shouldn't parse the output of ls(1)
答案 2 :(得分:0)
双引号将保留ls
命令到echo
命令的空格和新行,这就是当你使用双引号时你得到实际计数而不是使用引号的原因。 / p>
# echo hai\
> bye
haibye
# echo "hai
> bye"
hai
bye