脚本函数调用:function vs $(function)

Man*_*dan 3 bash shell-script function command-substitution

为简单起见,参考以下代码

#!/bin/bash

number=7

function doSomething() {
  number=8
}

doSomething
echo "$number"

Run Code Online (Sandbox Code Playgroud)

它打印8.

但与:

#!/bin/bash

number=7

function doSomething() {
  number=8
}

$(doSomething)
echo "$number"
Run Code Online (Sandbox Code Playgroud)

它打印7.

我有以下问题:

  • 每个的技术名称是什么?,我的意思是functioncall$(functioncall)
  • 每种方法如何工作?似乎前者考虑(影响)函数本身之外的变量,后者不考虑
  • 何时强制使用一种方法而不是另一种方法(主要是关于性能问题 - 当然 - 如果有的话),如果有其他原因,欢迎使用。

Adm*_*Bee 10

您正在体验命令替换的微妙之处。

电话

doSomething
Run Code Online (Sandbox Code Playgroud)

是一个简单的函数调用。它执行该函数,就像您已将该函数的命令复制并粘贴到您调用它的位置一样。因此,它number用新值覆盖变量8

电话

$(doSomething)
Run Code Online (Sandbox Code Playgroud)

另一方面是命令替换。它旨在执行函数并返回打印到的任何函数 stdout。它通常不用于“独立”,而是用于变量赋值,例如,

os_type=$(uname)
Run Code Online (Sandbox Code Playgroud)

这将执行命令uname,它在 Linux 系统上会打印Linux到控制台,并将其结果存储到 shell 变量中os_type。因此,将命令替换与不输出任何内容的命令或函数一起使用是没有意义的,例如您的doSomething. 实际上,由于替换$(doSomething)基本上是 输出的占位符,doSomething因此您没有收到脚本错误的唯一原因是您的函数不输出任何内容。你是否说过,例如,

$(uname)
Run Code Online (Sandbox Code Playgroud)

代替

$(doSomething)
Run Code Online (Sandbox Code Playgroud)

您的 shell 会尝试执行该命令Linux并生成一个

Linux: No such file or directory
Run Code Online (Sandbox Code Playgroud)

错误(1)

理解您观察到的效果的关键点是,在命令替换中,命令在子shell 中执行,即对变量所做的任何更改都不会反向传播到您执行主脚本的shell。因此,虽然它在内部运行 的命令doSomething并将变量设置number8,但它在自己的 shell 进程中执行此操作,该进程与运行脚本的 shell 进程无关(除了stdout正在检索它的事实),因此无法修改number您在主脚本中使用的变量。

如需进一步阅读,您可能需要查看

在这个网站上,或

了解更多概览。


(1)另一方面,这意味着您可以使用命令替换来执行在编写脚本时您不知道其名称的命令,但您可以通过执行另一个您知道的命令来找出该命令。