微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

bash – 命令替换什么时候产生比相同命令更多的subshel​​ls?

昨天有人建议,在bash中使用命令替换会导致不必要的subshel​​l被产生。建议是专门针对 this use case
# Extra subshell spawned
foo=$(command; echo $?)

# No extra subshell
command
foo=$?

最好我可以认为这个用例似乎是正确的。然而,一个试图验证这一点的快速搜索会导致混乱和矛盾的建议。似乎流行的智慧说,所有使用命令替换将产生一个subshel​​l。例如:

The command substitution expands to the output of commands. These commands are executed in a subshell,and their stdout data is what the substitution Syntax expands to. (07001)

这似乎很简单,除非你继续挖掘,在这种情况下,您将开始查找关于不是这样的建议的参考。

Command substitution does not necessarily invoke a subshell,and in most cases won’t. The only thing it guarantees is out-of-order evaluation: it simply evaluates the expressions inside the substitution first,then evaluates the surrounding statement using the results of the substitution. (07002)

这似乎是合理的,但这是真的吗? This answer一个subshel​​l相关的问题提示我,那个男人bash有这个要注意:

Each command in a pipeline is executed as a separate process (i.e.,in a subshell).

这带给我主要的问题。究竟是什么,将导致命令替换产生一个不会被产生的subshel​​l,无论如何孤立地执行相同的命令?

请考虑以下情况,并解释哪些引起了额外的子shell的开销:

# Case #1
command1
var=$(command1)

# Case #2
command1 | command2
var=$(command1 | command2)

# Case #3
command1 | command 2 ; var=$?
var=$(command1 | command2 ; echo $?)

这些对中的每一个是否需要执行相同数量的子shell? POSIX与bash实现有区别吗?是否还有其他情况下,使用命令替换会产生一个subshel​​l,其中运行相同的命令集在孤立不会?

更新和警告:

这个答案有一个困扰的过去,我自信地声称事实证明不是真的。我相信它现在有价值,但请帮助我消除其他不准确之处(或说服我完全删除它)。

我已经大量修改了 – 大部分是内脏的 – 这个答案在@kojiro指出我的测试方法是有缺陷的(我最初使用ps来寻找子进程,但这太慢了,总是会发现它们);下面描述一种新的测试方法

我原来声称并不是所有的bash子shell都运行在自己的子进程中,但事实证明不是真的。

正如@kojiro在他的回答中所说的,除了bash之外,有些shell有时避免为子shell创建子进程,所以一般来说在shell的世界中,不应该假设subshel​​l意味着子进程。

对于bash中OP的情况(假定命令{n}实例是简单的命令):

# Case #1
command1         # NO subshell
var=$(command1)  # 1 subshell (command substitution)

# Case #2
command1 | command2         # 2 subshells (1 for each pipeline segment)
var=$(command1 | command2)  # 3 subshells: + 1 for command subst.

# Case #3
command1 | command2 ; var=$?         # 2 subshells (due to the pipeline)
var=$(command1 | command2 ; echo $?) # 3 subshells: + 1 for command subst.;
                                     #   note that the extra command doesn't add 
                                     #   one

看起来像使用命令替换($(…))总是在bash中添加一个额外的subshel​​l,就像在(…)中包含任何命令一样。

我相信,但不能肯定这些结果是正确的;这是我如何测试(在OS X 10.9.1上的bash 3.2.51) – 请告诉我这种方法是否有缺陷:

确保只有2个交互式bash shell正在运行:一个运行命令,另一个用于监视。
>在第二个shell中,我使用sudo dtruss -t fork -f -p {pidOfShell1}来监视fork()调用(-f是必要的,也可以跟踪fork()调用“过渡”,即包括创建的通过子壳本身)。
>只在测试命令中使用内置的(no-op)(以避免用额外的fork()调用外部可执行文件来混淆图片);特别:

>:
> $(:)
>:| :
> $(:|

原文地址:https://www.jb51.cc/bash/387729.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐