POSIX sh 是否需要扩展 $!为了保留对子进程的引用?

POSIX sh 是否需要扩展 $!为了保留对子进程的引用?

规格

根据这个在线 POSIX 规范,在 Shell & Utilities, Shell Command Language, Section 2.9.3 Lists 中,有关异步列表的内容如下:

当异步列表的一个元素(列表中以 <&> 结尾的部分,例如命令1,上面)由 shell 启动,异步列表元素中最后一个命令的进程 ID 在当前 shell 执行环境中应该是已知的;请参阅 Shell 执行环境。该进程 ID 应保持已知状态,直到:

  • 命令终止,应用程序等待进程 ID。

  • $!在当前执行环境中展开“ ”(对应上一个异步列表)之前,会调用另一个异步列表。

该实现无需在当前 shell 执行环境中的已知进程 ID 列表中保留超过 {CHILD_MAX} 个最新条目。

其他相关引述:

  • 从同上,第 2.12 节 Shell 执行环境:

    shell执行环境由以下部分组成:

    […]

    • 该 shell 环境已知的异步列表中最后命令的进程 ID;请参阅异步列表
  • 从 Shell & Utilities、Utilities,请等待:

    当 shell 启动异步列表(请参阅异步列表)时,异步列表的每个元素中的最后一个命令的进程 ID 在当前 shell 执行环境中应为已知;请参阅 Shell 执行环境。

    […]

    如果在没有操作数的情况下调用等待实用程序,则它将等待,直到调用 shell 已知的所有进程 ID 都已终止并以零退出状态退出。

    […]

    已知进程 ID 仅适用于当前 shell 执行环境中的 wait 调用。

困惑

在 Bash 中,help wait指定“所有当前活动的子进程”。

该规范仅指定所有已知的进程 ID,并且调用另一个异步列表似乎会导致进程 ID 被“遗忘”。

如果我正确解释了 POSIX 规范,那么以下程序将只等待 5 秒:

#! /bin/sh
sleep 10 &
sleep 5 &
wait

$!由于之前没有出现过sleep 5 &,是不是IDsleep 10忘记了,没有等待?

同样,在两行之间插入: $!也不会被忘记,对吗?

让我尝试更清楚地阐述我的逻辑:

  1. 规格:已知的过程。 ID 是 shell 执行环境的一部分。让我们想象这是一些列表,因为实现细节并不重要。
  2. SPEC:运行command &会导致过程。该异步的 IDcommand为“已知”(IE,在列表中)。
    • SPEC(可疑,但请参阅第一个引用):运行command2 &而不以某种方式扩展$!会导致 proc.上一个命令的 ID 变为不再为人所知! (但现在已知 proc.ID。command2
  3. SPEC:wait不带参数仅使用已知的过程。身份证。
  4. 结论:因此,不强制$!异步命令之间的扩展会导致wait忘记等待某些子进程。

有些人认为wait等待所有进程。规范中提到“已知”进程,它有具体的定义。有些人认为“已知”指的是“in $!”即使规范没有说这样的事情(此外,“已知进程 ID”是复数数量,而$!不是)。

我同意这没有实际意义;当我开始新的工作时,shell 不会忘记我的工作。那么我在哪里误读了规范呢?

问题

  • POSIX 实际上是否需要使用$!for 来使wait不带参数的行为合理,例如在循环中启动异步列表时?
  • 是否有任何 shell(POSIX 或其他)实际上以这种方式实现规范(IE,实际上,我可以避免添加到: $! expand async. proc. ID to prevent forgetting it使用 nullary 的程序中吗wait

答案1

当您启动两个后台作业时,$!首先设置为第一个作业的 PID,然后设置为第二个作业的 PID。这并不意味着 shell 失去了对第一个作业的跟踪。 shell 也并不真正关心你用什么来做什么$!

请注意标准文本是如何表示wait不带任何参数的将等待全部后台工作?这与启动的后台作业数量以及您对该$!参数执行或不执行的操作无关。

您显示的示例中,两个睡眠调用在后台运行,保证等待两个调用终止,这意味着调用wait返回需要 10 秒。

相关内容