ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GNU Screen使用指南:解决SSH断线与终端复用难题

GNU Screen使用指南:解决SSH断线与终端复用难题 那台线上服务器我记得很清楚迁移脚本预计要跑四十分钟我敲下回车合上笔记本安心去吃午饭。回来一打开终端SSH早就断了脚本输出停在第三分钟进程没了这顿饭吃得格外昂贵。后来我养成一个习惯凡是需要长时间挂着不管的任务一定先放进screen会话里再做别的事。这篇文章就是围绕“screen使用”给你做一份能直接上手的实践笔记覆盖安装、会话管理、日志记录、配置调优以及在什么情况下你其实搜错了方向。适合刚接触 Linux 终端管理、经常跑后台任务的开发者也适合想把这套工具用得更顺手的老手。1. 为什么服务器上的长时任务总毁在“没装 screen”1.1 终端断开的一瞬间程序为什么就没了很多新手不理解为什么 SSH 断了正在跑的脚本也会跟着死原因在于程序不是你“点了个开始”就独立运行的它需要和你的终端保持联系——标准输入、标准输出、标准错误仍然绑定在终端上。SSH 连接一旦断开终端对应的主进程会收到挂断信号shell 退出前台任务失去了跟外界的通道随之被结束。你可以把终端和程序看成房东和房客的关系。房东把房门一关房客自然没法继续住。screen做的事情很简单在程序和你之间插进一个“二房东”它接管这套房间你和程序只是通过电话联系你挂断电话房间里的生活照常进行。也就是说screen是一个终端复用器负责维持一套虚拟终端即使你的 SSH 会话已经消失它仍然在服务器上坚定地跑着。1.2 screen 解决的三个真实痛点第一断线不丢进度。你在家里用笔记本连服务器跑任务网络卡一下人走开一下都不影响后台任务继续执行。第二一个 SSH 窗口同时开多个“工作台”。普通场景下你要开五个终端窗口就得建立五个 SSH 连接反复登录既慢又乱。screen一个会话里可以开多个窗口切来切去就像在一个 IDE 里开多个标签页。第三离开和回来是无缝的。你今天在公司开了一个screen会话关电脑回家到家再 SSH 上去screen -r刚才的工作现场原样恢复。注意这里不是“回放录屏”而是你回到了同一个还在跳动的会话里输出记录和运行状态都保留着。1.3 谁最需要这个东西运维人员跑部署脚本、开发人员挂日志采集、数据工程师做 ETL、算法工程师在服务器上训练模型这些场景都会因为一个 SSH 断线付出巨大代价。而screen的安装和使用成本极低装了不亏关键时候能救命。如果你只是在自己电脑上开个终端跑跑命令那它的作用没那么明显一旦你开始用 SSH 管理远程机器它就应该成为你的默认习惯。2. 装上它以及“bash: screen: command not found”的排查2.1 常见系统的安装命令绝大多数发行版都自带screen包但很多最小化安装、Docker 容器里没有。安装方式按系统区分系统/环境命令Debian / Ubuntusudo apt update sudo apt install screenCentOS / RHEL / Fedorasudo dnf install screen旧版用sudo yum install screenArch Linuxsudo pacman -S screenmacOSbrew install screen其他 Unix编译安装或通过系统包管理器搜索screen装完用screen -v看版本再用screen -ls试一下。第一次执行screen -ls出现No Sockets found in /run/screen/S-XXX.这种提示是正常的意思是当前还没有任何会话不代表出错。2.2 command not found 不一定是没装热词里出现频率很高的一句话是bash: screen: command not found。一开始你可能想当然是“没装”但还有几种常见情况软件包已经装了但当前 shell 的 PATH 没包含/usr/bin或/bin。比如某些脚本用sh执行时环境变量被精简过screen命令就找不到了。这时你在脚本里直接写全路径/usr/bin/screen是最省事的解法。你登录的用户不是普通用户或者容器里用的是极其精简的基础镜像确实没有安装。你改了 PATH覆盖了系统默认目录。用type -a screen和echo $PATH两条命令先确认路径情况。排查顺序建议这样先跑which screen有返回就说明装了问题在 PATH没有返回再跑ls -l /usr/bin/screen如果文件存在但which找不到同样说明 PATH 有问题如果文件都不存在就老老实实走安装步骤。很多刚上手的人在这一步反复卡住其实只是没分清“没安装”和“找不见”的区别。2.3 装完先验证三件事screen -ls能正常输出会话列表。直接输入screen能进入一个新的终端界面左上角有欢迎信息按CtrlA再按d能退出这个会话。再次执行screen -ls能看到类似12345.pts-0.hostname (Detached)的记录。验证通过说明终端复用能力已经就绪。接下来我们来把最常用的操作流程跑通。3. 掌握连接与脱离最常用的几个 screen 操作3.1 创建会话我建议永远带名字直接输入screen也能创建会话但它给你的标识是一串随机数字和终端名比如12345.pts-0.hostname。如果你开了三个会话回头根本分不清哪个是哪个。所以我建议从一开始就养成带-S参数命名的习惯screen -S deploy这会进入一个名字叫deploy的会话。会话名应该足够短、足够有含义。一个服务器上同时跑着日志采集、部署、调试三个任务名字就分别叫log-collector、deploy、debug一眼就能定位。3.2 核心流程跑任务、脱离、回来假设你要在远程服务器上执行一个耗时很长的数据压缩命令screen -S backup # 进入会话后执行 tar czf site-backup.tar.gz /var/www这时你想回家就按CtrlA松开后再按d。这个组合键的意思是“detach”——把会话从当前终端脱离留在后台继续跑。终端会回到原来的 shell并提示[detached from 12345.backup]。回家后连上服务器想看看任务跑完没有执行screen -ls screen -r backup-r就是重新 attach。你会看到压缩命令的输出画面仿佛从未离开过。任务如果已经结束screen -r进入后只会看到一个空 shell。3.3 一个会话开多个窗口我在实际使用中最常用的功能反而是 window 窗口。比如要同时看日志文件、编辑配置、执行命令没必要开三个 SSH直接在同一个screen会话里开多个窗口就够了。快捷键作用CtrlAc创建一个新窗口CtrlAn/CtrlAp切换下一个 / 上一个窗口CtrlA0~9直接跳到指定编号窗口CtrlA弹出窗口列表用方向键选择CtrlAA给当前窗口重命名方便识别举个实际工作流我在screen -S work里开了三个窗口。窗口 0 跑着实时日志窗口 1 用 vim 改配置窗口 2 放命令执行。切换时按CtrlA再按数字键高效到不行。3.4 退出会话别让僵尸会话堆积退出screen有几种方式在会话里输入exit或者按CtrlD只会关闭当前窗口窗口全部关闭后整个会话结束。按CtrlA再按\会提示是否退出全部窗口确认后整个会话结束。如果你已经脱离会话找不到它到底在哪个窗口可以直接在外面终止screen -S 会话名 -X quit。会话结束后过一段时间再用screen -ls查看可能会看到(Dead)状态的会话。这是进程结束但残留的 socket 文件用screen -wipe清理一下即可。我见过不少人的服务器上堆着几十个死会话都是因为从来不清理回头找真实会话时特别费劲。4. 记录日志防“跑丢了”screen 存日志的正确姿势4.1 先说清楚两种“看回放”的需求screen本身有两套和“记录”有关的功能很多人混在一起结果总是不满足。第一套是滚动缓冲区。你在会话里跑了一个脚本输出刷了几万行想往上翻看看开头。直接在正常终端里按PageUp往往只能看有限的内容因为默认的回滚行数很少。在screen里你可以按CtrlA再按[进入 copy 模式然后用方向键或者PageUp翻看之前的输出按Esc退出。这个模式只存在于当前会话内存中关掉会话就没有了。第二套才是真正的磁盘日志。你希望所有输出都实时写入文件那就需要打开 log 功能。4.2 启动时开启日志记录最简单的做法是创建会话时加-L参数screen -L -S deploy之后当前窗口中所有输出都会写入当前目录下的screenlog.0文件。如果你在同一个会话里开了第二个窗口它的日志会写到screenlog.1以此类推。如果你希望会话已经跑起来了再临时记录按CtrlA再按大写H屏幕左下角会出现类似logfile on的提示再按一次关闭。这个快捷键是 toggle不会影响窗口内容。4.3 硬拷贝把当前屏幕保存成一张“文字照片”有时候你不需要整段日志只想把当前屏幕内容留存下来按CtrlA再按小写h会生成一个hardcopy.N文件里面是当前屏幕所有文本。它有点像给终端拍了个快照特别适合记录执行结果、报错信息用于事后分析。注意它和-L日志的区别hardcopy 只有当前一屏log 是持续追加。4.4 日志文件怎么管理更好默认日志写在当前工作目录名字叫screenlog.N。问题在于你如果同时几个目录里都开了带-L的会话会有一堆screenlog.0、screenlog.1过几天自己都搞不清哪个属于哪个任务。我的建议是在~/.screenrc里指定一个固定日志目录和命名规则logfile /tmp/screen-%n-%S.log%n是窗口编号%S是会话名。这样文件名至少能看出会话名比单纯一个screenlog.0直观得多。4.5 日志会写爆磁盘吗screen记录的是程序的文本输出不是像素画面所以比视频产生的内容小得多。但如果你的程序每秒钟疯狂打印日志文本量同样会膨胀。我习惯在做长任务时先估算一下输出量如果程序本来就会写独立日志文件那就没必要再开screen -L让screen只负责“挂住进程”就好。只有任务输出完全没有落盘、只往终端打的时候才值得靠screen的日志功能补齐这一步。5. 把 screen 调教顺手配置文件与更多实战习惯5.1 一份能满足日常的 .screenrcscreen的默认界面很朴素也正因为朴素很多新手觉得它“不值钱”。实际上把它调教好之后体验完全不输给各类新式终端复用工具。下面这份~/.screenrc配置我用了很多年# 关闭启动欢迎信息 startup_message off # 回滚缓冲提升到 10000 行 defscrollback 10000 # 关闭响铃时的闪屏 vbell off # 常驻底部状态栏显示当前窗口 caption always %{ kw} %-w%{ gk}%n*%t%{-}%w % %c # 日志文件命名 logfile /tmp/screen.%S-%n.log逐行解释startup_message off让你进入screen时不再看到那页欢迎说明少按一次回车对老手来说省心。defscrollback 10000把 copy 模式下能回看的行数从默认几百行提升到一万行调试长输出时非常有用。vbell off关掉终端闪屏提示避免后台任务触碰边界时屏幕闪一下吓人。caption always最重要的就是这一行。它会在窗口底部常驻一条状态栏显示当前窗口编号和标题配合CtrlA的窗口切换逻辑你的方向感立刻就有了。logfile配合上一节的日志管理需求让每个会话的日志落在固定路径。5.2 后台创建一个会话跑完不留痕有一种更“优雅”的用法是不进入会话直接让screen在后台启动一个会话并执行命令。举个例子screen -dmS train -L bash -c python train.py train_output.txt 21这条命令分解一下-dmSdetach 模式启动会话名是train。-L打开日志记录。bash -c ...在会话里执行一段命令。执行后你立即回到普通 shellscreen -ls能看到一个train会话在后台跑。想跟进进度就screen -r train。这种方式适合在部署脚本、CI 流程里使用不需要有人一直守在前台。5.3 多人协作看同一个会话screen有个很实用的附加能力多终端 attach 同一个会话。你和一个同事需要一起排查线上问题他在他自己的终端里执行screen -x deploy就能看到你所在的deploy会话当前画面你可以操作他也能看到两个人不用互相截图了。需要注意这不是远程桌面控制更像共享一块屏幕同一时刻只有一个人输入操作时多打招呼避免互相抢输入。5.4 我踩过的几个反模式几乎每个用screen的人都会经历一段混乱期我总结几个典型不建新窗口所有窗口都堆在一个会话里导致窗口列表几十个切起来没法分辨。解决办法是从创建会话那一刻就给窗口命名。嵌套使用screen。你在screen会话里又执行screen按CtrlA时不知道切的是哪一层。如果确实需要嵌套向内部会话发送CtrlA的快捷键是CtrlA再按a这个技巧能救急但强烈建议你别这么做。会话结束不清理。尤其跑完任务直接关闭终端留下一堆 detached 和 dead 会话后面screen -r时看到一堆要选的反而心烦。我的习惯是任务结束立刻exit关干净。6. 别混淆这个 screen 不是 pygame 的 screen也不是录屏软件如果你是因为下面几个场景搜到“screen”这个词那要小心你可能走错片场了。6.1 pygame 里的 screen 是绘图画布热词里有import pygame; pygame.init()screen 这类内容指的是 Python pygame 库里的显示表面。它的常用写法是这样的import pygame import random pygame.init() w, h 800, 600 screen pygame.display.set_mode((w, h)) pygame.display.set_caption(My Game) running True while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False screen.fill((30, 30, 30)) pygame.display.flip() pygame.quit()这里的screen是一个游戏窗口对应的 Surface 对象。所有图形、文字、图片都绘制到这个screen上最后调用pygame.display.flip()把绘制结果显示到窗口。它跟 Linux 终端里的screen命令没有任何关系只是都叫“屏幕”而已。新手最容易踩的坑是init()之后忘了创建 display surface或者绘制完没调flip()窗口一直白着。6.2 录屏软件、分屏工具、整页截图的搜索方向Leawo Screen Recorder 是 Windows 平台的录屏工具。关于注册激活我建议走官方渠道试用免费且好用的替代品是 OBS StudioWindows 11 自带的 Xbox Game Bar 也支持屏幕录制。Universal Split Screen 是一款窗口分屏布局工具帮你在显示器上把多个程序按区域排列跟终端复用完全两码事。full page capture 通常指浏览器整页截图扩展和“终端会话挂后台”也没有任何关系。6.3 怎么快速判断你要找的是哪一个我给自己定了一条判断规则场景里出现 SSH、远程、断线、后台任务这些词毫无疑问是 GNU Screen出现 Python、pygame、窗口、游戏循环是 pygame 的 display surface出现“录制屏幕”“录像”是录屏软件出现“分屏”“多窗口布局”是窗口管理工具。想清楚这一点就不会在错误的方向上浪费几个小时。我现在拿到一台新服务器第一件事就是把screen装上配置好.screenrc这已经成为肌肉记忆。它不炫目也不算最年轻但稳定、轻量、随处可得这才是它在 Linux 世界里一直没被淘汰的原因。
返回列表