【问题标题】:Why aren't single-command pipelines executed in subshells?为什么不在子 shell 中执行单命令管道?
【发布时间】:2018-03-31 01:55:34
【问题描述】:

我的bash 4.4.19 版手册页说:

管道

管道是由控制运算符||& 之一分隔的一个或多个命令的序列。管道的格式为:

[time [-p]] [ ! ] command [ [|||&] command2 ... ]

当然。那讲得通。然后,在该部分的后面:

管道中的每个命令都作为单独的进程执行(即,在子外壳中)。

也是合理的,容易证明的:

$ pwd
/Users/ravron
$ ls | grep src  # yes, src _does_ exist
src
$ cd src | true  # cd in subshell has no effect on parent session
$ pwd
/Users/ravron

但是,我注意到上面对管道的定义是这样的,即使是一个简单的命令也是一个管道。毕竟,在语法中,除了command 之外的所有内容都是可选的:

[time [-p]] [ ! ] command [ [|||&] command2 ... ]

当然,现在,即使是在子 shell 中运行单个命令(man bash 术语中的“简单命令”)也将非常无用。 cd 不起作用,变量设置不起作用,等等。然而,现实——尽管简单的命令匹配(相当退化的)管道的语法,但不会在子 shell 中执行——似乎与手册页。以列表形式,这是我的理解:

  • 管道的语法意味着简单的命令也是管道。
  • 手册页说管道中的命令在子 shell 中运行。
  • 简单的命令不在子 shell 中运行。

我错过了什么,或者这是man bash 中公认的无关紧要的错误?

【问题讨论】:

  • 如果您想要真正的规范性文档,该文档是由语言律师为之奋斗的,那应该是pubs.opengroup.org/onlinepubs/9699919799/utilities/…。请注意,单命令情况 明确描述为管道。
  • ...但是,请参阅该标准的第 2.9.1 节,“命令搜索和执行”小节,将内置的行为排除在“单独的实用程序”中发生的 execve() 的通常要求之外环境”。

标签: bash


【解决方案1】:

手册不够精确。 POSIX 规范(第 2.12 节)更明确(我添加的粗体):

此外,多命令管道的每个命令都在一个 subshel​​l 环境;然而,作为扩展,任何或所有命令 管道可以在当前环境中执行。所有其他 命令应在当前shell环境中执行。

bash,默认情况下,将每个子shell 实现为子进程。 (bash 4.2 中引入的lastpipe 选项让最终命令在当前 shell 环境/进程中执行。)

shell 的语法说管道可以包含一个或多个命令,但 shell 的语义区分一个命令的管道和两个或多个命令的管道。

【讨论】:

    【解决方案2】:

    手册从未定义过“subshel​​l”这个词。虽然您可能直观地假设子shell 始终是原始shell 的子进程,但单个命令的退化情况使用原始shell 进程作为子shell。

    其他一些 shell 走得更远,总是在原始 shell 的管道中运行最后一个命令。

    【讨论】:

    • 难道“管道中的每个命令都作为一个单独的进程执行”与此相矛盾吗?
    • @ravron,将与其他管道组件分开,而不是将与调用外壳分开
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多