'ls'和'echo $(ls)'之间的区别


27

考虑两个壳样本

$ ls
myDoc.html
SomeDirectory
someDoc.txt

$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt

ls我了解,第一个执行将把当前工作目录的内容附加到stdout文件(这是终端显示的内容)。它是否正确?

第二个采用ls命令的值(表示当前工作目录的内容)并将其打印到stdout文件中。它是否正确?

为什么两个命令给出不同的输出?


1
因为你在做回声。ls的输出作为echo命令的输入。
ankidaemon '16

这是“预期的”行为,很快就会有人解释。但是,您确定ls本身不会给您每行多个项目吗?
roaima

@roaima列的ls是bsd“功能”的残余。Unix版本每行打印一个条目
Steve Cox,

@SteveCox自早期SVR4以来,我还没有使用过适当的UNIX,所以我的记忆有些模糊。谢谢你提醒我。
roaima

为什么不echo *呢?
jdh8

Answers:


70

运行此命令时:

ls

终端显示的输出ls

运行此命令时:

echo $(ls)

shell捕获的输出$(ls)并对其进行分。使用default IFS,这意味着所有空格序列(包括换行符)都将被单个空格替换。这就是为什么输出echo $(ls)显示在一行上的原因。

有关分词的高级讨论,请参阅Greg的FAQ

抑制分词

外壳程序不对引号中的字符串执行单词拆分。因此,您可以使用以下命令抑制字分割并保留多行输出:

echo "$(ls)"

ls 和多行输出

您可能已经注意到,ls有时每行打印多个文件:

$ ls
file1  file2  file3  file4  file5  file6

当输出ls到终端时,这是默认设置。当输出不直接发送到终端时,ls将其默认值更改为每行一个文件:

$ echo "$(ls)"
file1
file2
file3
file4
file5
file6

在中记录了此行为man ls

另一个微妙之处:命令替换和尾随换行符

$(...)命令替换,shell从命令替换输出中删除尾随换行符。这通常不会引起注意,因为默认情况下,echo会在其输出末尾添加一个换行符。因此,如果您从末尾丢失了一个换行符,$(...)而从中获得了一个换行符echo,则没有任何变化。但是,如果命令的输出以2个或多个换行符结尾而echo仅加回一个,则您的输出将丢失一个或多个换行符。例如,我们可以printf用来生成尾随换行符。请注意,尽管换行数不同,以下两个命令仍会产生相同的空白行输出:

$ echo "$(printf "\n")"

$ echo "$(printf "\n\n\n\n\n")"

$ 

在中记录了此行为man bash

另一个惊喜:路径名扩展了两次

让我们创建三个文件:

$ touch 'file?' file1 file2

观察之间的差异ls file?echo $(ls file?)

$ ls file?
file?  file1  file2
$ echo $(ls file?)
file? file1 file2 file1 file2

在的情况下echo $(ls file?),文件glob file?会扩展两次,从而导致文件名file1file2在输出中出现两次。正如Jeffiekins所指出的那样,这是因为路径名扩展首先在ls运行之前由Shell 执行,然后在echo运行之前再次执行。

如果我们使用双引号,则可以抑制第二个路径名扩展

$ echo "$(ls file?)"
file?
file1
file2

4
另外,使用isatty可以检查stdout是否是tty,ls使用它来确定是否使用颜色。
Janus Troelsen

1
上一个代码片段中的引号不匹配吗?还是$( )实际上提供了语法障碍,所以您不需要插值?

6
@cat $()提供语法障碍。
Random832

2
另一个重要的区别是:如果任何文件名包含通配符,该echo命令将扩展通配符。例如,如果ls返回文件?file1 file2,那么echo $(ls)将返回文件吗?file1 file2 file1 file2
Jeffiekins '16

1
@Jeffiekins echo不会扩展通配符;在将产生的扩展作为参数传递之前,shell会做echo
chepner

0

ls 知道它是否正在将输出发送到终端。

ls在命令提示符处执行将写入您的伪tty。重定向的输出ls通常不会使用伪tty,而是以ls不同的格式设置输出。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.