得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

断开 ssh 继续运行命令

为什么 ssh 断开后运行的命令会退出呢?

明确元凶:

SIGHUP 信号

简单的来说:

因为所有进程都得有个父进程。当 ssh 到一个服务器上时,打开的 shell 就是所有执行命令的父进程,当断开 ssh 连接后,在 ssh 中运行命令的父进程就没了。如果处理不当,这些进程就会收到 SIGTERM 信号,全被干掉了

详细的原因:

在 Linux/Unix 中,有这样几个概念:

  1. 进程组(process group):一个或多个进程的集合,每一个进程组有唯一一个进程组 ID,即进程组长进程的 ID

  2. 会话期(session):一个或多个进程组的集合,有唯一一个会话期首进程(session leader)。会话期 ID 为首进程的 ID

  3. 会话期可以有一个单独的控制终端(controlling terminal)。与控制终端连接的会话期首进程叫做控制进程(controlling process)。当前与终端交互的进程称为前台进程组,其余进程组称为后台进程组。

根据 POSIX.1 定义:

  1. 挂断信号(SIGHUP)默认的动作是终止程序

  2. 当终端接口检测到网络连接断开,将挂断信号发送给控制进程(会话期首进程)

  3. 如果会话期首进程终止,则该信号发送到该会话期前台进程组

  4. 一个进程退出导致一个孤儿进程组产生时,如果任意一个孤儿进程组进程处于 STOP 状态,发送 SIGHUP 和 SIGCONT 信号到该进程组中所有进程

因此当网络断开或终端窗口关闭后,也就是 ssh 断开后,控制进程收到 SIGHUP 信号退出,会导致该会话期内其他进程退出

解决方法:

要么让进程忽略 SIGHUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程
  1. nohup

    1
    $ nohup ping baidu.com &
  2. setsid

    1
    $ setsid ping baidu.com &
  3. ()

    1
    $ (ping baidu.com &)
  4. disown

    1
    2
    3
    4
    5
    6
    7
    8
    $ ping baidu.com
    # 按 ctrl+z 挂起进程
    [1]+ Stopped ping baidu.com
    $ bg %1
    [1]+ ping baidu.com &
    $ jobs
    [1]+ Running ping baidu.com
    $ disown -h %1
  5. 使用 screen 这一类辅助程序

either I will find a way, or I will make one.