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

Owe*_*wen 33 shell

考虑两个壳样本

$ ls
myDoc.html
SomeDirectory
someDoc.txt
Run Code Online (Sandbox Code Playgroud)

$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt
Run Code Online (Sandbox Code Playgroud)

第一个执行ls,据我所知,将当前工作目录的内容附加到stdout文件中(这是终端显示的内容)。这样对吗?

第二个获取ls命令的值(这意味着是当前工作目录的内容)并将其打印到stdout文件中。这样对吗?

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

Joh*_*024 76

当您运行此命令时:

ls
Run Code Online (Sandbox Code Playgroud)

终端显示ls.

当您运行此命令时:

echo $(ls)
Run Code Online (Sandbox Code Playgroud)

shell 捕获输出$(ls)并对其进行分。默认情况下IFS,这意味着所有空格序列(包括换行符)都被单个空格替换。这就是为什么输出echo $(ls)出现在一行上。

有关分词的高级讨论,请参阅Greg 的常见问题解答

抑制分词

Shell 不会对引号中的字符串执行分词。因此,您可以通过以下方式抑制分词并保留多行输出:

echo "$(ls)"
Run Code Online (Sandbox Code Playgroud)

ls 和多行输出

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

$ ls
file1  file2  file3  file4  file5  file6
Run Code Online (Sandbox Code Playgroud)

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

$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Run Code Online (Sandbox Code Playgroud)

此行为记录在man ls.

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

$(...)命令替换,shell 从命令替换的输出中删除尾随的换行符。这通常不会引起注意,因为默认情况下echo会在其输出的末尾添加一个换行符。所以,如果你从末失去一个换行符$(...),并且获得一个距离echo,没有任何改变。但是,如果您的命令的输出以2 个或更多换行符结尾,而echo只添加一个,则您的输出将缺少一个或多个换行符。例如,我们可以使用printf生成尾随换行符。请注意,尽管换行数不同,以下两个命令都会产生一个空行的相同输出:

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

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

$ 
Run Code Online (Sandbox Code Playgroud)

此行为记录在man bash.

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

让我们创建三个文件:

$ touch 'file?' file1 file2
Run Code Online (Sandbox Code Playgroud)

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

$ ls file?
file?  file1  file2
$ echo $(ls file?)
file? file1 file2 file1 file2
Run Code Online (Sandbox Code Playgroud)

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

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

$ echo "$(ls file?)"
file?
file1
file2
Run Code Online (Sandbox Code Playgroud)

  • @cat `$()` 提供了语法障碍。 (6认同)
  • 此外,使用 `isatty` 可以检查 stdout 是否为 tty,ls 使用它来确定是否使用颜色。 (4认同)
  • 一个更重要的区别:如果任何文件名包含通配符,`echo` 命令将*扩展通配符*。例如,如果 `ls` 返回 **file? file1 file2**,然后`echo $(ls)` 会返回 **file? 文件 1 文件 2 文件 1 文件 2**。 (2认同)