为什么Unix后台进程有时会在我退出shell时终止?

12

我想知道为什么在Bash shell中的后台进程会出现不同的行为

情况1:使用Putty(SSH)登录Unix服务器

  • 默认使用csh shell
  • 我改变为bash shell
  • 输入"sleep 2000 &"
  • 按回车键

它给了我作业号。 现在我通过单击putty窗口中的"x"来结束了我的会话。然后打开另一个会话并尝试查找该进程...该进程已经死亡。

情况2:使用Putty(SSH)登录Unix服务器

  • 默认使用csh shell
  • 我改变为bash shell
  • vi mysleep.sh
  • sleep 2000 & 保存mysleep.sh
  • ./mysleep.sh

不同之处在于,我将sleep命令存储在文件中并执行该文件,而非直接执行sleep命令。

现在我通过单击putty窗口中的"x"来结束了我的会话。然后打开另一个会话并尝试查找该进程...该进程仍然存在。

不确定为什么会出现这种情况。 我以为我需要在bash中进行disown才能在注销后运行进程。

我发现父进程ID中的一个差异。在第二种情况下,sleep 2000的父进程ID变为1。看起来当mysleep.sh的进程死亡时,内核将父进程分配给了1。

4个回答

20

这里的区别确实在于中间的过程。当你关闭终端窗口时,会向其中运行的进程发送一个HUP信号(如0匿名0coward所提到的与“nohup”相关)。接收到HUP信号的默认操作是关闭 - 参见signal(3)手册页。

 No    Name         Default Action       Description
 1     SIGHUP       terminate process    terminal line hangup
在您的第一个例子中,睡眠进程直接接收到HUP信号并退出,因为它没有设置做其他事情的操作。(有些进程会捕获HUP信号并使用它来执行某些操作,例如重新读取一些配置文件)
在第二个例子中,运行Shell脚本的Shell进程已经退出,因此睡眠进程永远不会收到信号。在UNIX中,由于wait(2)族调用和进程的内部工作方式,每个进程都必须有一个父进程。因此,当父进程死亡时,内核将其作为寄养子女交给init(pid 1,如您所指出)。 孤儿进程(维基百科)提供了更多信息,另请参见僵尸进程获取额外的技术细节。

8

已经在运行的进程?

^z
bg
disown %<jobid>

新进程/脚本(在本地计算机控制台上)?

nohup script.sh &

新进程/脚本(在远程计算机控制台上)?

根据您的需要,
有两个选项[将会有更多;-)]

ssh remotehost 'nohup /path/to/script.sh </dev/null > nohup.out 2>&1 &'

或者

使用'screen'


1
这并没有回答楼主的问题。 - Chinasaur

3
尝试使用 "nohup cmd args..." 命令。

0

Steven的回答是正确的,但我想再次强调这里的棘手部分:

=> 使用一个仅在后台执行sleep的bash脚本

这样做的效果是,“脚本”几乎立即退出(因为它已经完成了所有命令)。然而,在其生命周期内它确实创建了一个子进程(sleep)。这样做的效果是:

  • “脚本”不再能成为父进程,而sleep则变成了孤儿进程,由init接管(这在pstree中很好地显示出来)
  • 您从中启动脚本的bash shell不再有底层作业

请注意,所有这些都发生在您执行脚本时,与任何ssh注销/putty关闭无关。

当您最终关闭putty会话时,bash会收到“SIGHUP”,但不会将其转发给任何其他进程(因为没有剩余的作业) 在另一种情况下,bash仍然有一个作业,然后将其发送给SIGHUP,导致它结束(正如您所注意到的那样)

希望这可以帮助到您


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接