iBu*_*Bug 5 shell pipe io-redirection posix shell-builtin
考虑以下命令:
exit > /dev/null
exit | cat
Run Code Online (Sandbox Code Playgroud)
在一些 shell(ksh、bash、(d)ash)上,行为是相同的:第一个命令导致 shell 立即退出,而第二个命令没有可见的行为。
我得出的结论是,第一个命令不涉及 fork(2),而第二个命令涉及两个(一个用于执行exit
,另一个用于 execve(2) cat
)。
我查看了 POSIX 规范第 2.14 节,但没有找到任何明确说明这一点的内容。
POSIX 是否指定某些命令不得 fork(2) 而另一些命令必须?标准是否可以接受为第一个命令生成子 shell?
我知道( exit )
永远不应该退出当前 shell,因为括号会生成一个实际执行命令的子 shell exit
,这意味着子 shell 将立即退出。但是,我不确定重定向和管道,因为这里没有括号。
我问这个问题是因为在最近的课程实验室中,我们被告知要实现一个最小的 Unix shell。我们可以实现许多“可选功能”,以供补充。这些“可选功能”之一是组合重定向和管道。我们有一些不同的实现,我相信其中一些比其他实现更接近 POSIX 的指定行为,因此我想知道实际行为是如何指定的。
好吧(退出),
exit实用程序应使 shell从 当前执行环境退出[...]
和 ( 2.12. Shell 执行环境)
子 shell 环境应创建为 shell 环境的副本,[...]此外,多命令管道的每个命令 都位于子 shell 环境中;然而,作为扩展,管道中的任何或所有命令都可以在当前环境中执行。所有其他命令都应在 当前 shell 环境中执行。
因此,exit
管道中的 运行在它自己的执行环境/子 shell 中,并且仅退出,而简单命令中的 则exit > /dev/null
运行在主 shell 环境中。(正如评论中所指出的,重定向根本不会真正影响它。)
请注意,第二个引号中间的部分意味着某些 shell 可能会运行主环境中管道的所有命令,因此即使在这种情况下也会退出整个 shell。在实践中,更常见的是对管道的最后一个命令执行此操作。
在 Bash 中lastpipe
,例如:
$ bash -c 'true | exit; echo end.'
end.
Run Code Online (Sandbox Code Playgroud)
但
$ bash -O lastpipe -c 'true | exit; echo end.'
Run Code Online (Sandbox Code Playgroud)
不打印任何内容。