for thing in foo bar; do { background_processor $thing cleanup_on_exit $thing } & done
这样做我想要的:我运行start.sh,它退出与代码0,并且两个subshell运行在后台.每个subshell运行background_processor,当它退出时,它运行cleanup_on_exit.即使我退出我最初运行start.sh的终端(即使是ssh连接)也是如此.
然后我试过这个:
ssh user@host "start.sh"
除此之外,start.sh已经退出,ssh显然也等待子shell退出.我真的不明白为什么一旦start.sh退出,subhells成为pid 1的孩子,他们甚至没有分配一个tty …所以我不明白他们如何仍然与我的ssh连接相关联.
后来我试过:
ssh -t user@host "start.sh"
现在这些进程有一个分配的伪tty.现在,我发现一旦start.sh退出,ssh就会退出,但它也会杀死子进程.
我猜到在后一种情况下,子进程正在发送SIGHUP,所以我这样做:
ssh -t user@host "nohup start.sh"
这实际上有用!所以,我有一个解决我的实际问题的解决方案,但我想在这里了解SIGHUP / tty的细节.
总之,我的问题是:
>为什么ssh(没有-t)等待子进程即使在start.sh退出之后,即使它们有父pid 1?
>为什么ssh(with -t)杀死子进程,显然是用SIGHUP,即使从终端运行终端并注销该终端也不会发生这种情况?
- Why does ssh (without -t) wait for the child processes even after start.sh exits,even though they have parent pid 1?
因为没有tty,ssh通过管道(然后由孩子继承)连接到shell进程的stdin / stdout / stderr,而我正在使用的OpenSSH版本(OpenSSH_4.3p2)等待这些套接字关闭退出.一些较早版本的OpenSSH没有这样做.有一个很好的解释,有理由,here.
相反,当使用交互式登录(或ssh -t)时,ssh和进程正在使用TTY,因此没有管道等待.
我可以通过重定向流来恢复我想要的行为.该变体立即返回:ssh user @ host“start.sh< / dev / null> / dev / null 2>& 1”
- Why does ssh (with -t) kill the child processes,apparently with a SIGHUP,even though that does not happen when I run them from a terminal and log out of that terminal?
因为bash是以非交互模式开始的,这意味着默认情况下禁用作业控制,因此子进程与父bash进程(即会话引导者)处于同一进程组中.当父bash进程退出时,内核将发送SIGHUP到其进程组(位于前台),如setpgid(2)中所述:
If a session has a controlling terminal,… [and] the session leader exits,the SIGHUP signal will be sent to each process in the foreground process group of the controlling terminal.
相反,当使用交互式登录时,bash处于交互模式,这意味着默认情况下启用作业控制,因此子进程进入单独的进程组,并且在退出时不会收到SIGHUP.
我可以通过使用set -m来恢复我想要的行为,以启用bash中的作业控制.如果我将set -m添加到start.sh,那么当ssh退出时,这些子代不再被杀死.
神秘解决:)