用 screen 工具来执行耗时的任务


一、前言

作为 Linux 服务器管理员,经常要使用 SSH 登陆到远程 Linux 机器上做一些耗时的操作。

也许你遇到过使用 Telnet 或 SSH 远程登录 Linux ,运行一些程序。如果这些程序需要运行很长时间(几个小时),而程序运行过程中出现网络故障,或者客户机故障,这时候客户机与远程服务器的链接将终端,并且远程服务器没有正常结束的命令将被迫终止。

又比如你 SSH 到主机上后,开始批量的 SCP 命令,如果这个 SSH 线程断线了,SCP 进程就中断了。在远程服务器上正在运行某些耗时的作业,但是工作还没做完快要下班了,退出的话就会中断操作了,如何才好呢?

摘自:screen linux 命令 – 51yip.com

还有,为什么我们把终端窗口一关掉或者 SSH 掉线进程就会终端呢?元凶其实是 SIGHUP 信号!

根据 POSIX 定义:元凶其实是 SIGHUP 信号的默认动作是终止程序,而且当终端窗口监测到网络断开连接时,会发送 SIGHUP 信号给当前终端运行的所有进程。

所以,程序自然就终止了!那有什么解决办法吗?当然有!那就是 screen。


二、screen 介绍和用法

screen 可以看作是一个窗口管理器命令行界面版本。它提供了统一的管理多个会话的界面和相应的功能。

摘自:GNU Screen – 维基百科

screen 最大的优点就是:只要 SCREEN 进程没有被终止,即使网络断开或者关闭了终端窗口,在里面运行的进程都不会受到影响!

2.1 screen 命令说明

Use: screen [-opts] [cmd [args]]
 or: screen -r [host.tty]

Options:
-4            Resolve hostnames only to IPv4 addresses.
-6            Resolve hostnames only to IPv6 addresses.
-a            Force all capabilities into each window's termcap.
-A -[r|R]     Adapt all windows to the new display width & height.
-c file       Read configuration file instead of '.screenrc'.
-d (-r)       Detach the elsewhere running screen (and reattach here).
-dmS name     Start as daemon: Screen session in detached mode.
-D (-r)       Detach and logout remote (and reattach here).
-D -RR        Do whatever is needed to get a screen session.
-e xy         Change command characters.
-f            Flow control on, -fn = off, -fa = auto.
-h lines      Set the size of the scrollback history buffer.
-i            Interrupt output sooner when flow control is on.
-l            Login mode on (update /var/run/utmp), -ln = off.
-ls [match]   or
-list         Do nothing, just list our SockDir [on possible matches].
-L            Turn on output logging.
-m            ignore $STY variable, do create a new screen session.
-O            Choose optimal output rather than exact vt100 emulation.
-p window     Preselect the named window if it exists.
-q            Quiet startup. Exits with non-zero return code if unsuccessful.
-Q            Commands will send the response to the stdout of the querying process.
-r [session]  Reattach to a detached screen process.
-R            Reattach if possible, otherwise start a new session.
-s shell      Shell to execute rather than $SHELL.
-S sockname   Name this session <pid>.sockname instead of <pid>.<tty>.<host>.
-t title      Set title. (window's name).
-T term       Use term as $TERM for windows, rather than "screen".
-U            Tell screen to use UTF-8 encoding.
-v            Print "Screen version 4.01.00devel (GNU) 2-May-06".
-wipe [match] Do nothing, just clean up SockDir [on possible matches].
-x            Attach to a not detached screen. (Multi display mode).
-X            Execute <cmd> as a screen command in the specified session.

很多……同样的,我们当然不需要用到这么多。下面介绍几个常用的方法。

2.2 screen 常用方法

2.2.1 新建一个虚拟终端

现在用 screen 命令新建一个虚拟终端(可以指定终端名):

screen  [-S <终端名>]

如果出现提示语,按回车键即可跳过。

Screen version 4.00.03 (FAU) 23-Oct-06

Copyright (c) 1993-2002 Juergen Weigert, Michael Schroeder
Copyright (c) 1987 Oliver Laumann
...
#按回车键跳过
[root: ~]#              
#屏幕被清空,说明已进入新建的虚拟终端。

好了,现在我们就在虚拟终端里了!我们用 screen -ls 命令查看一下现在虚拟终端的号码和状态。

screen -ls
There are screens on:
        46790.pts-0.zenandidi   (Attached)    #当前正在使用编号为 46790 的虚拟终端
1 Sockets in /var/run/screen/S-root.

没问题。那我们就在里面执行下 ping 命令吧。

ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.057 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.092 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.082 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.069 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.082 ms
64 bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.069 ms
......

2.2.2 在虚拟终端中出来

现在我们先按 Ctrl+A 再按 D 切出来。

#先按  Ctrl+A 再按 D
[detached from 46790.pts-0.zenandidi]  #当前已从编号为46790的虚拟终端中切换出来
screen -ls
There is a screen on:
    46790.pts-0.zenandidi   (Detached)  #编号为46790的虚拟终端正在后台运行
1 Socket in /var/run/screen/S-root.
[root: ~]# 登出   #从虚拟终端里面出来之后,可以按下 Ctrl+D 退出实体终端了

如果已经把持续时间很长的任务放在了虚拟终端里面的话,现在可以放心地按 Ctrl+D 关闭终端窗口或者断开 SSH 连接了。

2.2.3 恢复到虚拟终端内

我已经断开了 SSH 连接然后重新连上服务器了,现在来看看刚才的虚拟终端是否还在。

screen -ls
There is a screen on:
    46790.pts-0.zenandidi    (Detached)  #编号为 46790 的虚拟终端仍然后台运行

现在我们用 screen -r <虚拟终端编号> 命令恢复进去:

screen -r 46790

(如果刚才创建终端的时候指定了名字,那么可以使用 screen -r <终端名> 恢复。)

64 bytes from 127.0.0.1: icmp_seq=51 ttl=64 time=0.128 ms
64 bytes from 127.0.0.1: icmp_seq=52 ttl=64 time=0.104 ms
64 bytes from 127.0.0.1: icmp_seq=53 ttl=64 time=0.084 ms
64 bytes from 127.0.0.1: icmp_seq=54 ttl=64 time=0.063 ms
64 bytes from 127.0.0.1: icmp_seq=55 ttl=64 time=0.067 ms
64 bytes from 127.0.0.1: icmp_seq=56 ttl=64 time=0.061 ms
64 bytes from 127.0.0.1: icmp_seq=57 ttl=64 time=0.062 ms
......

可以看到,命令没有因为退出终端而终止了。

2.2.4 虚拟终端内的其他快捷键

只能在虚拟终端里操作

  • 先按 Ctrl+A 再按 D :从虚拟终端中切换出来。
  • 先按 Ctrl+A 再按 C :新建一个虚拟终端。
  • 连续按 Ctrl+A :在虚拟终端之间切换。
  • 先按 Ctrl+A 再按 P :切换到前一个虚拟终端。
  • 先按 Ctrl+A 再按 N :切换到后一个虚拟终端。
  • 先按 Ctrl+A 再按 K :杀死一个虚拟终端(需要按一下 y 回车确认)。

三、screen 常用命令总结和注意事项

3.1 实体终端命令

screen :新建一个虚拟终端
screen -ls :列出当前运行的虚拟终端
screen -r <虚拟终端编号> :恢复到指定编号的虚拟终端中

3.2 虚拟终端命令

  • 先按 Ctrl+A 再按 D:从虚拟终端中切换出来。
  • 先按 Ctrl+A 再按 C:新建一个虚拟终端。
  • 连续按 Ctrl+A :在虚拟终端之间切换。
  • 先按 Ctrl+A 再按 P:切换到前一个虚拟终端。
  • 先按 Ctrl+A 再按 N:切换到后一个虚拟终端。
  • 先按 Ctrl+A 再按 K :杀死一个虚拟终端(需要按一下 y 回车确认)。

3.3 注意事项

  • 在虚拟终端里切换出来的时候,注意不要直接按 Ctrl+D,而是先按 Ctrl+A 再按 D
  • 需要创建多个虚拟终端时,请先切换到物理终端来再使用 screen 命令或者先按 Ctrl+A 再按 C,不要嵌套使用 screen 命令。嵌套使用 screen 命令切换可能会物理终端的时候会导致后面创建的虚拟终端全部停止运行。

发表评论