echo $(ls) 中的括号和 $ 符号是什么意思

echo $(ls) 中的括号和 $ 符号是什么意思

输出

# ls

# echo $(ls)

是一样的。$符号和括号到底是什么意思?

另外,从技术层面上讲发生了什么,导致这两个命令的输出相同?

答案1

这是 bash 的命令替换。

命令替换允许命令的输出替换命令本身。当命令以下列方式括起来时,就会发生命令替换:

 $(command) or

 `command`

http://www.gnu.org/software/bash/manual/bashref.html#Command-Substitution

更多的:

http://tldp.org/LDP/abs/html/commandsub.html

http://wiki.bash-hackers.org/syntax/expansion/cmdsubst

与您的问题类似的一个很好的例子:

http://bashshell.net/shell-scripts/using-command-substitution-in-a-bash-shell-script/

答案2

当 shell 遇到 中包含的文本时$( ),它会:

  1. 将其视为命令,并且(作为豹子说)在子壳
  2. 替代输出命令的一部分,代替整个表达式。任何尾随的$(...)换行符从此输出中删除。
  3. 如果不是,则进行进一步扩展$(...)(见下文)。

作为heartsmagic 的答案解释道,这是两种可用语法之一为了命令替换

“什么……导致这两个命令的输出相同?”

实际上,输出结果不太ls常见确切地与输出相同echo $(ls)

ek@Io:~/tmp$ ls
bar  foo
ek@Io:~/tmp$ echo $(ls)
bar foo

ls通常用两个或多个空格或换行符分隔文件名。这有助于我们更容易区分它们,尤其是因为文件名中的空格比较常见(但多个连续的空格不太常见)。

单词拆分

当我跑步的时候echo $(ls),发生了以下的事情。

  1. 命令替换替换$(ls)为:

    bar
    foo
    

    听到这个你可能会感到惊讶,因为这可能不是你ls单独运行时看到的结果!输出结果的这种差异将在下面解释,但实际上这并不是你最终在这两个单词之间出现一个空格的原因。如果用(有两个空格)替换,ls也会发生同样的事情。$(ls)bar foo

  2. 随后,shell 执行单词拆分,单独bar处理foo参数echo命令中,而不是作为包含空格的单个参数。

    通配符*如果命令的输出包含、?[,那么也会执行(又名文件名/路径名扩展) 。

    详情如下,引用双引号允许命令替换但抑制单词拆分和通配。

什么时候echo接收多个参数(除了像 这样的选项-n,它们会被特殊处理并且根本不会打印),它会将它们全部打印出来,并在后续参数之间留一个空格。echo然后打印一个换行符,除非-n传递了选项。

因此echo $(ls)显示的输出类似于bar foo而不是bar foo

如果你运行ls并且它没有列出任何文件,或者只有一个文件,则输出ls经常与 的输出相同echo $(ls)。即便如此,它也不会总是相同,例如当文件名包含除孤立(单个)空格以外的空格时:

ek@Io:~/tmp2$ touch 'my   file'
ek@Io:~/tmp2$ ls
my   file
ek@Io:~/tmp2$ echo $(ls)
my file

ls打印多个文件时,其输出不太可能与的输出完全相同$(ls)。同样:

  • echo a becho $(echo a b)产生相同的输出,
  • echo 'a b'echo $(echo 'a b')不要。

关于命令替换,有一件很重要的事情需要了解——未加引号的命令替换会受到单词拆分(和通配)的影响

引用

如果你想预防单词拆分通配符--而且你通常将要想要阻止它们——您可以将命令替换表达式括在双引号( " ")。使用双引号而不是单引号的原因是单引号更强;它们会抑制命令替换。

这也适用于参数扩展,这是一种更常用的shell 扩展而不是命令替换,算术扩展. 引用命令替换很重要的原因(除了在相当不常见的情况之外)是知道您希望进一步扩展)与引用参数扩展的原因

终端检测

双引号通常足以避免命令替换导致意外结果。特别是,它可以与echo上面基于的示例以及ls目录中包含单个包含空格的条目的示例一起使用:

ek@Io:~/tmp2$ echo "$(ls)"
my   file

但是,如上所述,您可能会惊讶地发现,运行时看到的内容ls通常不是传递给的echo内容"$(ls)"

ek@Io:~/tmp$ ls
bar  foo
ek@Io:~/tmp$ echo "$(ls)"
bar
foo

这是因为ls检查标准输出是一个终端决定如何格式化其输出,当没有明确指定输出格式时。

  • 当 stdout 是终端时,ls以垂直排序列输出,如ls -C
  • 当 stdout 不是终端时,ls将每个条目列在其自己的行上,例如ls -1

在命令替换中,标准输出不是终端,因为命令的输出不会直接发送到终端供您查看 - 相反,它被 shell 捕获并用作另一个命令的一部分。

为了在通过命令替换运行时获得多列格式ls,请向其传递-C标志:

ek@Io:~/tmp$ echo "$(ls -C)"
bar  foo

(有时被建议作为和的dir替代ls -C也会起作用尽管如此,dir表现得像ls -C -b而不仅仅是ls -C

Shell 别名

另一个原因ls可能有时表现不同,echo "$(ls)"可能lsshell 别名。运行alias ls检查;在 Ubuntu 上你通常会得到alias ls='ls --color=auto'。这使得当它ls作为你以交互方式运行的命令的第一个单词出现时(并且在非交互式 shell 中启用了别名扩展的不太常见的情况下),它会被替换为ls --color=auto

例如,当我运行时ls,它会列出蓝色的目录和绿色的可执行文件(并且也遵守许多其他着色规则)。当标准输出是终端时,--color=auto会打印彩色输出,否则不会。ls

ls为了在通过命令替换运行时获得彩色输出,传递给--color--color=always选项。如果您愿意,可以将其与以下内容结合使用-C

echo $(ls -C --color)

请注意,虽然你可以为或创建ls一个别名来代替,并且不关心标准输出是否是终端……当通过命令替换调用时,该别名仍然不会导致产生彩色输出。这是因为 shell 别名(在ls --colorls --color=alwaysls --color=autols --color=alwaysls伯恩风格的贝壳喜欢狂欢) 仅当 shell 将它们视为命令的第一个单词时才会展开,并且它们不会被子 shell 继承。

答案3

()$()用于在子 shell 中运行命令。

http://tldp.org/LDP/abs/html/subshel​​ls.html了解详情。

答案4

在变量名前使用 $ 会调用赋给变量的值。没有 $ 的 Echo 只会将变量名打印到屏幕(或标准输出)上。

相关内容