简体   繁体   English

为什么在分组命令中执行简单命令不分叉子shell进程,而复合命令将执行此操作

[英]Why does executing a simple command in a grouping command does not fork a subshell process, and the compound command will do it

I know that grouping commands (command-list) creates a subshell environment , and each listed command is executed in that subshell . 我知道分组命令(command-list)创建了一个子shell环境 ,每个列出的命令都在该子shell中执行。 But if I execute a simple command in the grouping command, (use the ps command to output the processes), then no subshell process is output . 但是如果我在grouping命令中执行一个简单的命令,(使用ps命令输出进程), 则不输出子shell进程 But if I tried to execute a list of commands ( compound command ) in the grouping command, then a subshell process is output . 但是,如果我尝试在分组命令中执行命令列表( 复合命令 ),则输出子shell进程 Why does it produce such a result? 为什么会产生这样的结果?

  • A test of executing a simple command (only a ps command) in a grouping command: 在分组命令中执行简单命令 (仅ps命令)的测试:
     [root@localhost ~]# (ps -f) 
    with the following output: 具有以下输出:
     UID PID PPID C STIME TTY TIME CMD root 1625 1623 0 13:49 pts/0 00:00:00 -bash root 1670 1625 0 15:05 pts/0 00:00:00 ps -f 
  • Another test of executing a compound command (a list of commands) in a grouping command: 在分组命令中执行复合命令 (命令列表)的另一个测试:
     [root@localhost ~]# (ps -f;cd) 
    with the following output: 具有以下输出:
     UID PID PPID C STIME TTY TIME CMD root 1625 1623 0 13:49 pts/0 00:00:00 -bash root 1671 1625 0 15:05 pts/0 00:00:00 -bash root 1672 1671 0 15:05 pts/0 00:00:00 ps -f 

I tested a lot of other commands (compound commands and simple commands), but the results are the same. 我测试了很多其他命令(复合命令和简单命令),但结果是一样的。 I guess even if I execute a simple command in a grouping command, bash should fork a subshell process, otherwise it can't execute the command. 我想即使我在分组命令中执行一个简单的命令, bash应该分叉一个子shell进程,否则它不能执行命令。 But why can't I see it? 但为什么我不能看到它?

Bash optimizes the execution. Bash优化了执行。 It detects that only one command is inside the ( ) group and calls fork + exec instead of fork + fork + exec . 它检测到只有一个命令在( )组内并调用fork + exec而不是fork + fork + exec That's why you see one bash process less in the list of processes. 这就是为什么你在流程列表中看到一个bash流程较少的原因。 It is easier to detect when using command that take more time ( sleep 5 ) to eliminate timing. 使用占用更多时间( sleep 5 )来消除时序时更容易检测。 Also, you may want to read this thread on unix.stackexchange. 此外,您可能希望在unix.stackexchange上阅读此线程

I think the optimization is done somewhere inside execute_cmd.c in execute_in_subshell() function (arrows > added by me): 我认为,优化内部某处做execute_cmd.cexecute_in_subshell()函数(箭头>由我添加的):

 /* If this is a simple command, tell execute_disk_command that it
     might be able to get away without forking and simply exec.
>>>> This means things like ( sleep 10 ) will only cause one fork
     If we're timing the command or inverting its return value, however,
     we cannot do this optimization. */

and in execute_disk_command() function we can also read: execute_disk_command()函数中我们还可以读取:

/* If we can get away without forking and there are no pipes to deal with,
   don't bother to fork, just directly exec the command. */

It looks like an optimization and dash appears to be doing it too: 它看起来像一个优化和破折号似乎也这样做:

Running 运行

bash -c '( sleep 3)' & sleep 0.2 && ps #or with dash

as does, more robustly: 同样,更强大:

strace -f -e trace=clone dash -c '(/bin/sleep)' 2>&1 |grep clone # 1 clone

shows that the subshell is skipped, but if there's post work to be done in the subshell after the child, the subshell is created: 显示子shell被跳过,但如果在子shell之后的子shell中有后期工作,则创建子shell:

strace -f -e trace=clone dash -c '(/bin/sleep; echo done)' 2>&1 |grep clone #2 clones

Zsh and ksh are taking it even one step further and for (when they see it's the last command in the script): Zsh和ksh甚至更进了一步(当他们看到它是脚本中的最后一个命令时):

strace -f -e trace=clone ksh -c '(/bin/sleep; echo done)' 2>&1 |grep clone # 0 clones

they don't fork (=clone) at all, execing directly in the shell process. 他们根本没有fork(= clone),直接在shell进程中执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM