bash如何处理等待后台子命令?

时间:2013-11-19 17:07:13

标签: bash unix wait

在bash中,如果我执行命令(sleep 60) & wait,那么bash将等待60秒完成,但如果我执行(sleep 60 &); wait则不会发生等待。这两种情况(幕后)的根本区别是什么?

2 个答案:

答案 0 :(得分:0)

  

if I execute (sleep 60 &); wait then no waiting occurs.

这是因为sleep 60 &在分叉子进程的后台运行而不是在当前进程中运行。当wait在当前进程中运行时,它没有任何等待的工作。

对于前。当你跑:

(sleep 60) &

child sleep process仅进入当前shell的作业,因此wait可以正常工作。

要测试此功能,您可以运行:

jobs -l <​​/ p>

并查看后台作业中的睡眠过程:

[2]+ 74103 Running                 ( sleep 60 ) &

答案 1 :(得分:0)

我将借助于打印进程'pid及其父级pid的程序来说明这一点。

$ cat getpids.c
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

main()
{
    printf("%d %d\n", (int)getpid(), (int)getppid());
    exit(10);
}

$ echo $$
2002

我们的shell是2002年的过程。

$ ./getpids
2651 2002

这表明getpids是在shell的子进程中运行的。

$ (./getpids)& wait
[1] 2656
2656 2002
[1]+  Exit 10                 ( ./getpids )

getpids再次在shell的子进程中运行。 shell等待它并显示其退出状态。

$ (./getpids&); wait
$ 2658 1

这里,getpids是init的一个子进程1.这意味着,当它调用getppid()时,它的父进程已退出。

$ ./getpids
2663 2002

Shell 2002仍然存在。发生的事情是,在这种特殊情况下,shell决定(command&)值得在shell的fork中运行。那个分叉的shell再次分叉,启动了getpids,然后在getpids开始运行getppid()调用之前退出。

我们可以通过strace查看系统调用来更仔细地查看。

2002  clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb77c5938) = 2657
2002  wait4(-1,  <unfinished ...>
2657  clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb77c5938) = 2658
2657  exit_group(0)                     = ?
2002  <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 2657
2658  execve("./getpids", ["./getpids"], [/* 22 vars */]) = 0

Shell 2002 forks并创建shell 2657,它会分叉并创建进程2658然后退出。 Shell 2002等待并看到退出的进程2657。 Shell 2658,现在是“孤儿”,因此拥有父pid 1,执行./getpids。