当你使用 SSH 或者 telent 远程登录到 Linux 服务器的时候,是不会经常为一些需要长时间执行的任务感到头疼?比如系统备份、编译安装、大数据传输等等。通常这种情况会为这样的任务开一个远程终端窗口。因为他们执行的时间太长,在此期间可不能关掉窗口或者断开连接,否则这个任务就被杀掉了,一切就白忙了。
SIGHUP 信号
首先让我们来了解为什么关闭窗口或者断开链接会导致正在运行的进程终结
在 Linux/Unix 中有这样的几个概念:
- 进程组(process group):一个或多个进程的集合,每一个进程组有唯一一个进程组 ID,即进程组长进程的 ID。
- 会话期(session):一个或多个进程组的集合,有唯一一个会话期首进程(session leader)。会话期 ID 为首进程的 ID。
- 会话期可以有一个单独的控制终端(controlling terminal)。与控制终端连接的会话期首进程叫做控制进程(controlling process)。当前与终端交互的进程称为前台进程组。其余进程组称为后台进程组。
根据 POSIX.1(不了解的请自行 Wiki,或者等我再水一篇)定义:
- 挂断信号(SIGHUP)默认的动作是终止程序。
- 当终端接口检测到网络连接断开,将挂断信号发送给控制进程(会话期首进程)。
- 如果会话期首进程终止,则该信号发送到该会话期前台进程组。
- 一个进程退出导致一个孤儿进程组中产生时,如果任意一个孤儿进程组进程处于 STOP 状态,发送 SIGHUP 和 SIGCONT 信号到该进程组中所有进程。
因此当网络断开或终端窗口关闭后,控制进程收到 SIGHUP 信号退出,会导致该会话期内其他进程退出。
现在让我们通过一个例子来看。打开两个 SSH 终端,在其中一个运行 top 命令
[root@hxkvm ~]# top
在另一个终端找到 top 的进程 ID 为 13575 其父进程为 13514
[root@hxkvm ~]# ps -ef|grep top
root 13575 13514 0 19:17 pts/0 00:00:00 top
root 13577 13546 0 19:17 pts/2 00:00:00 grep --color top
使用 ps-xj 命令可以看到:
[root@hxkvm ~]# ps -xj|grep 13575
13512 13514 13514 13514 pts/0 13575 Ss 0 0:00 -bash
13514 13575 13575 13514 pts/0 13575 S+ 0 0:00 top
13546 13669 13668 13546 pts/2 13668 S+ 0 0:00 grep --color 13575
关闭第一个 SSH 窗口可以看到 TOP 也被杀掉了
[root@hxkvm ~]# ps -ef|grep 13575
root 13814 13546 0 19:50 pts/2 00:00:00 grep --color 13575
如果能做到忽略 SIGHUP 信号,关闭窗口断开链接就不会影响程序的运行了。nohup 命令可以达到这个目的,如果程序的标准输出/标准错误是终端,nohup 默认将其重定向到 nohup.out 文件。值得注意的是 nohup 命令只是使得程序忽略 SIGHUP 信号,还需要使用标记**&**把它放在后台运行。
nohup <``command``> [argument…] &
Screen
虽然 nohup 很容易使用,但还是比较“简陋”的,对于实行简单的操作行,对于复杂的场景就很麻烦了。
我们可以使用一个更为强大的实用程序 screen,流行的 Linux 发行版通常会自带,如果没有请自行安装。
[root@hxkvm ~]# rpm -qa|grep screen
screen-4.1.0-0.23.20120314git3c2946.el7_2.x86_64
简单来说,Screen 是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen 中有会话的概念,用户可以在一个 screen 会话中创建多个 screen 窗口,在每一个 screen 窗口中就像操作一个真实的 telnet/SSH 连接窗口那样。在 screen 中创建一个新的窗口常用方式:
一、直接在命令行输入 screen
Screen 将创建一个执行 shell 的全屏窗口。你可以执行任意 shell 程序,就像在 ssh 窗口中那样。在该窗口中键入 exit 退出该窗口,如果这是该 screen 会话的唯一窗口,该 screen 会话退出,否则 screen 自动切换到前一个窗口。
二、Screen 命令后跟你要执行的程序
Screen 创建一个执行该程序的单窗口会话,退出该程序将退出该窗口/会话
我更加习惯 Screen 目录以现在 blog 的 PIPE 程序为例,
screen -S pipe
./pipe
这样就可以保证 pipe 的运行不会因为断开 putty 而中断运行。
想要重新切换回运行的窗口直接:
screen -R pipe
当然 screen 也是支持快捷键操作的,这种命令形式在 screen 中叫做键绑定(key binding),C-a 叫做命令字符(command character)
可以通过 C-a ?
来查看所有的键绑定(C 即 Ctrl+),常用的键绑定有:
C-a ? | 显示所有键绑定信息 |
---|---|
C-a w | 显示所有窗口列表 |
C-a C-a | 切换到之前显示的窗口 |
C-a c | 创建一个新的运行 shell 的窗口并切换到该窗口 |
C-a n | 切换到下一个窗口 |
C-a p | 切换到前一个窗口(与 C-a n 相对) |
C-a 0..9 | 切换到窗口 0..9 |
C-a a | 发送 C-a 到当前窗口 |
C-a d | 暂时断开 screen 会话 |
C-a k | 杀掉当前窗口 |
C-a [ | 进入拷贝/回滚模式 |
Screen 提供了丰富强大的定制功能。你可以在 Screen 的默认两级配置文件/etc/screenrc 和 $HOME/.screenrc 中指定更多,例如设定 screen 选项,定制绑定键,设定 screen 会话自启动窗口,启用多用户模式,定制用户访问权限控制等等。如果你愿意的话,也可以自己指定 screen 配置文件。
以多用户功能为例,screen 默认是以单用户模式运行的,你需要在配置文件中指定 multiuser on 来打开多用户模式,通过 acl*(acladd,acldel,aclchg...)命令,你可以灵活配置其他用户访问你的 screen 会话。更多配置文件内容请参考 screen 的主页。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于