☰
ZeroTermux 内置 GNU Screen 会话管理与分屏键位速查
2026/10/23 3:56:44 网站建设 项目流程

手机上的终端跑着跑着,切个应用回来,编译进程没了,日志停在半截,这种事我经历过不止一次。后来我把所有耗时超过三分钟的命令统统塞进 screen 里跑,情况才彻底改观。ZeroTermux 内置的 screen 就是 GNU Screen 本体,会话管理、窗口操作、键位这套东西跟在桌面 Linux 上完全一致,唯一的差别是:你的手指要在几英寸的屏幕上敲出一个 Ctrl 前缀。这份手册就是把我自己反复查、反复忘、反复重新翻文档的那部分整理出来,包含会话的完整生命周期、窗口与分屏的操作逻辑、一张能贴在显示器边上的键位速查表,以及几个只有真在手机上用才会遇到的坑。不管你是刚装上 ZeroTermux 想跑个脚本,还是已经用了半年但始终只用Ctrl-a d这一个组合键,下面这些内容应该都能捞到点东西。

1. 先想清楚:为什么在移动终端里要优先学 screen

1.1 我为什么放弃了"多开几个终端页签"的做法

刚上手的那段时间,我的习惯是开三四个终端页签,一个跑服务、一个看日志、一个敲命令。这套做法在桌面端勉强能用,在手机上很快就崩了。第一个崩点是内存,每个页签背后都是一整套 shell 进程和它启动的子进程,页签开多了,切回来的时候系统已经把其中几个回收掉,日志看到一半发现进程被挂起,得重新手动恢复。第二个崩点是状态丢失,页签是界面层的概念,跟进程本身没有绑定关系,应用被切到后台、被系统判定为可回收,页签还在,里面的进程已经没了。

screen 解决的正是这个问题。它把自己放在终端和 shell 之间,扮演一个"会话容器"的角色。你在 screen 里跑的东西,父进程是 screen 的守护进程,而不是那个随时可能被系统掐掉的终端界面。界面没了不要紧,容器还在,进程还活着,你重新连上来,一切照旧。这个差别在手机上被放大了十倍,因为手机上"界面消失"是常态,不是异常。

所以我的建议很直接:如果你在 ZeroTermux 里跑的东西超过了三分钟,就先套一层 screen,再往下敲命令。这个习惯不需要成本,screen -S 名字六个字符的事。

1.2 会话、窗口、区域:三个概念必须先分清

很多人用 screen 用得别扭,根子在概念没理顺。GNU Screen 的模型其实只有三层,但中文翻译容易混,我用一张表把它固定下来。

层级英文类比生命周期对应操作
会话session一间办公室独立于终端存在,可脱离可恢复screen -S新建,-r恢复
窗口window办公室里的工位依附于会话,会话不死窗口就在Ctrl-a c新建,Ctrl-a n切换
区域region工位上摆几块屏幕依附于当前窗口,只是显示切分Ctrl-a S水平切,Ctrl-a |垂直切

关键在于理解"区域"不是"窗口"。分屏之后你在一个窗口里看到的是同一块终端画面被切成几份,这几份里跑的是不同的窗口内容,但容器依然是同一个会话、同一个当前窗口的显示空间。这个设计带来的一个直接后果是:分屏不会增加进程隔离度,只是让你同时看几样东西。想要真正的隔离,还是得开新窗口或者新会话。

1.3 它不适合干什么:把边界划在前面

screen 不是万能的,我在几个场景里试过,最后都换回了别的方案。

一个是需要图形化交互的场合,比如要在手机上看一个需要鼠标点击的 TUI 程序,screen 对鼠标事件的支持非常有限,转义序列一多就容易错乱。另一个是多人协作审计,screen 支持多显示同时附加,但它的权限模型极其简单,谁拿到终端谁就是主人,不适合需要区分权限的场景。还有一个是作为服务常驻,screen 的存活依赖宿主应用不被彻底清掉,真要长期跑还是得靠系统级的调度机制,screen 在这里只是"减少丢失概率",不是"保证不丢"。

把这三条边界记住,后面遇到问题就不会往错误的方向排查。我见过有人花两小时研究 screen 为什么在应用被彻底划掉之后进程还是没了,答案是它本来就不负责这件事。

2. 前缀键与状态栏:读懂 screen 的交互模型

2.1 默认前缀为什么是 Ctrl-a,冲突又从哪来

screen 的所有管理命令都挂在"前缀键"上,默认是Ctrl-a。选它的历史原因很简单:在屏幕编辑器(比如 vi)里,Ctrl-a是一个相对低频的组合,不会跟高频编辑操作打架。但这个方法在今天的 shell 环境里已经不那么保险了。

最典型的冲突来源是行编辑器的"行首"快捷键。很多 shell 的 emacs 模式把Ctrl-a绑定成"跳到行首",你按下去,屏幕立刻跳转、字母 a 反而没打出来。还有嵌套场景:你在普通 shell 里敲Ctrl-a没事,一旦在 screen 里再套一层 screen,外层会先吃掉这个按键。我在手机上还遇到过第三种情况,某些输入法的实体键映射把Ctrl和音量键绑在一起,误触概率明显上升。

判断方法很简单:按下Ctrl-a然后按?,如果弹出 screen 的帮助页,说明前缀键正常工作;如果只是光标动了一下或者屏幕上出现一个字母,那就是被外层吃掉了。这种情况下换前缀键是最干脆的做法,具体改法在第 5 章给。

2.2 从按键到动作:一条命令的完整路径

理解 screen 的按键处理顺序,能省掉很多"为什么没反应"的困惑。当你按下Ctrl-a,screen 进入一个短暂的"等待下一键"状态,这个状态下它拦截一切输入,不往下传给 shell。接着你按的第二个键被解释为一条命令。

这套机制带来两个实用推论。第一,Ctrl-a之后按Ctrl-a是"把前缀键本身发给 shell",也就是说你要往终端里输入一个真正的Ctrl-a字符,就连按两次。第二,如果你按了前缀之后反悔了,按一个不存在的组合,screen 通常会提示 "No screen binding",而不是把这两个按键透传下去,这意味着前缀键后面的那次按键被吞掉了,得重按。手机上误触的代价比桌面高,因为重新输入一段命令更麻烦。

还有一层:Ctrl-a :打开的是 screen 自己的命令行,这里的输入走的是 screen 的命令解析器,不是 shell。常见的误操作是在这里敲 shell 命令,然后发现报 "Unknown command"。

2.3 状态栏那一行字,每个字段都是信息

默认状态下 screen 会在底部留一行,内容大概是这样的:

0$ bash 1-日志 2*服务

从左到右读:0是窗口编号,$表示这个窗口上次有没有活动(*表示当前窗口,-表示这个窗口自上次查看后没输出,$我没记错的话是当前窗口但无输出的标记),后面是窗口名称,再往后是其他窗口的编号和名字。切到别的窗口,*会跟着移动,你可以一眼看出哪个窗口正在刷日志。

这行字的价值在手机屏幕上被放大了。竖屏一行能显示的窗口数量有限,超过四五个就挤在一起看不全,这时候按Ctrl-a w弹出一个完整的窗口列表更实用。列表里会显示编号、名称和状态,用方向键选择、回车跳转,比一个个按数字快。

如果你觉得这行状态栏占地方,可以在配置里关掉或者改成更紧凑的格式。我自己的做法是保留它,但把格式压到最短,只显示编号和名字,因为屏幕上每一行都很宝贵。

3. 会话生命周期:从新建到清理的完整链路

3.1 新建会话时 -S 和 -t 到底差在哪

新建会话就一条命令,但参数容易搞混:

screen -S work # 给会话命名 screen -S work -t main # 命名会话,同时给第一个窗口命名 screen # 匿名会话,名字由系统按 PID 生成

-S命名的是会话,这个名字会出现在screen -ls的列表里,是恢复时用来定位的标识。-t命名的是会话里第一个窗口的标题,显示在状态栏上。两者不冲突,可以同时用。我现在的固定写法是screen -S proj -t shell,会话名用项目缩写,窗口名用用途,恢复的时候一眼就能找到。

匿名会话不是不能恢复,但名字是一串数字,screen -ls里一排12345.pts-0.xxx看着就头大。除非是临时用一下,否则建议都起名。命名还有个额外好处:支持前缀匹配。screen -r pro能匹配到proj,只要没有歧义,不用敲全名。

一个细节:会话名里不要带空格和特殊字符,恢复时的参数解析会出问题。我踩过一次,名字里带了个点,screen -r死活匹配不上,最后只能screen -ls抄了完整 PID 才进去。

3.2 detach 与 reattach:这条链路的每个环节都要清楚

进入 screen 之后,脱离的方式是Ctrl-a d。屏幕会闪一下,回到你原来的 shell,提示[detached from 12345.work]之类。这时候 screen 进程还在后台跑,你跑的东西也还在。

恢复的写法有好几种,适用场景完全不同:

命令行为适用场景
screen -r work恢复指定会话只有一个显示附加,最常用
screen -r恢复唯一会话只有一个会话时省事,多个会报错
screen -d work强制把别处的附加踢掉上次脱离失败,界面还"占着"
screen -d -r work先踢掉再恢复手机端口最常见的组合
screen -x work附加到已附加的会话(共享)想同时看两个显示
screen -D -RR自动找最近会话并强制恢复记不住名字时的懒人写法

我用得最多的是screen -d -r。原因很实际:手机上的 screen 经常进入一种"以为还附着,其实界面早没了"的状态,直接-r会提示 "Session is already attached",加上-d先把那个僵尸显示踢掉再恢复,一次成功。

-x要慎用。它不是"恢复",是"共享",两个显示同时操作同一个会话,两个终端都会刷新同一份画面,尺寸取两者较小的那个。手机上偶尔用一次看看别人在跑什么还行,日常别用,容易把自己搞晕。

3.3 screen -ls 的输出怎么读,Dead 会话怎么处理

screen -ls的输出看起来简单,实际信息量不小:

$ screen -ls There are screens on: 8421.work (Detached) 8433.log (Attached) 8450.tmp (Dead ???) 3 Sockets in /data/data/<包名>/files/home/.screen.

四个状态要能区分开。Detached是正常的、没被附加的会话,可以直接-r。Attached是已经被某个显示占用的会话,想接管就得先-d。Dead ???是会话的进程已经死了但套接字文件还留在目录里,这种不能恢复,只能清理。还有一种Multi开头的,表示有多个显示同时附加。

清理 Dead 会话用screen -wipe,它会把失效的套接字文件删掉,不会再出现在列表里。别手动去.screen目录删文件,虽然能删掉,但 screen 内部的状态没同步,有时候会留下更奇怪的残留。

套接字目录的路径在输出最后一行,通常是 HOME 下的.screen。ZeroTermux 的 HOME 落在应用私有数据区,形如/data/data/<应用包名>/files/home。这个路径值得记一下,因为偶尔需要进去看看到底有哪些会话文件,或者磁盘紧张的时候排查。

3.4 后台保活:screen 能做的和不能做的

很多人以为用了 screen 就万事大吉,结果手机锁屏十分钟,进程照样没了。这里必须说清楚责任划分。

screen 保证的是"终端界面断开之后,会话还在"。它不保证"操作系统不会杀进程"。Android 有一套自己的进程优先级策略,你的应用切到后台、内存紧张的时候,整个应用的进程组都可能被回收,screen 的守护进程也在里面,一起走。

能做的有几件事。一是把应用加入电池优化的白名单,减少被判定为可回收的概率。二是如果环境里带了申请唤醒锁的能力(很多这类终端应用会提供一个命令或者通知栏里的开关),在跑长任务之前打开它,让 CPU 别进入深度休眠。三是尽量让屏幕保持亮着,或者用系统的"保持唤醒"选项,虽然费电但最可靠。四是任务本身要能断点续跑,这个是兜底,不管前面做得多好,总有意外。

我自己的做法是:跑超过半小时的任务,一定先开唤醒锁,同时把中间结果定期落盘,screen 只是减少了我重新开始的次数,不是让我可以不管。

4. 窗口与分屏:把一块小屏幕用出多任务的效率

4.1 窗口的创建、切换与重命名

会话之内的操作,绝大多数时间花在窗口上。核心就几个键,但每个都有讲究。

新建窗口是Ctrl-a c,新窗口会继承当前窗口的工作目录(这个特性很贴心,你在某个项目目录下开新窗口,直接就在同一层)。切换用Ctrl-a n(下一个)和Ctrl-a p(上一个),这两个是循环的,窗口多了按起来效率不高。

编号跳转是Ctrl-a 0到Ctrl-a 9,直接定位到对应编号的窗口。这里有个细节:编号不是顺序的,你关掉窗口 2,后面的窗口不会自动补位,编号会留空。想重新编号得手动做,在Ctrl-a :的命令行里输入number 2,把当前窗口改成 2 号。

按名字跳转是Ctrl-a ',会提示输入编号或者名字前缀。窗口起了好名字的话,这个比记数字方便。名字用Ctrl-a A改,输入后回车生效。我习惯按用途命名,比如log、db、edit,比0 1 2 3有信息量得多。

关窗口是Ctrl-a k,会要一次确认。直接按Ctrl-a \是"杀掉所有窗口并退出 screen",这个不确认,误触之后会话就没了,我在手机上误按过一次,正在跑的东西全断了。所以要么把Ctrl-a \的绑定解掉,要么养成按完前缀先停半秒的习惯。

4.2 分屏的操作逻辑与手机上的取舍

分屏是 screen 里体验差异最大的部分。桌面上一分为二看日志和敲命令很爽,手机上竖屏分完,每块只剩十几行,实际价值有限。我的结论是:横屏 + 分屏尚可一用,竖屏不如开两个窗口来回切。

操作本身不难。Ctrl-a S(大写 S)水平切分,屏幕上下分成两块。Ctrl-a |(竖线)垂直切分,左右两块,这个需要较新版本的 screen 支持,老版本会报未知命令。切完之后用Ctrl-a Tab在区域之间切换焦点,焦点所在区域会有明显的边界提示(取决于终端能力,有些终端只能靠光标位置判断)。

关闭当前区域用Ctrl-a X(大写)。只保留当前区域、关掉其他所有区域用Ctrl-a Q。注意Ctrl-a Q不是"关掉当前区域",语义正好相反,我一开始总记反。

分屏里新建窗口比较绕。你在某个区域里按Ctrl-a c,新窗口会显示在当前焦点区域,原来的内容被顶掉,但窗口还在,用Ctrl-a n能切回来。想让某个已有的窗口显示到当前区域,用Ctrl-a :然后输入screen 编号,或者更简单,切到那个区域之后按Ctrl-a '选择窗口。

手机上一个特别实用的技巧:分屏状态下临时想全屏看某一块,不需要关掉另一半,直接Ctrl-a Q关掉其他区域,看完之后重新Ctrl-a S切回来。虽然重建分屏不是"恢复",但窗口本身没丢,内容还在。

4.3 窗口的搬运与跨会话移动

有些操作平时用不到,关键时刻能救场。Ctrl-a {和Ctrl-a }是交换当前窗口和前一个/后一个窗口的位置,纯粹为了整理顺序,功能上等价于重新编号,但不需要记编号。

Ctrl-a X之外还有个Ctrl-a :remove,这个是把当前窗口从会话里"摘出去",落到一个编号靠后的位置。摘出去之后可以用Ctrl-a :输入screen 编号重新挂回来,也可以理解成"临时藏起来"。

跨会话移动窗口,比如把一个窗口从 A 会话挪到 B 会话,这个 screen 本身支持得不太好,官方的方式是在目标会话里 attach 源会话的显示,实际上做不到。我试过几次,最后放弃了,真需要就是在新会话里重开一个窗口,把命令重跑一遍。别在这上面浪费时间。

顺带说一个容易忽略的点:窗口的编号和名字是绑在会话上的,你把整个会话 detach 再 reattach,窗口的编号、名字、顺序、当前窗口位置全都保留。这是个好消息,意味着你可以在 detach 之前把布局整理好,下次进来直接开工。

5. 键位速查与配置:一份能直接用的清单

5.1 分组速查表

我把常用的键按用途分了五组,打印出来贴在桌边比每次按Ctrl-a ?快。

分组键位作用
会话Ctrl-a d脱离当前会话
会话Ctrl-a :quit退出 screen(需确认)
会话Ctrl-a \杀掉所有窗口并退出,慎用
窗口Ctrl-a c新建窗口
窗口Ctrl-a n/Ctrl-a p下一个 / 上一个窗口
窗口Ctrl-a 0~9跳到指定编号窗口
窗口Ctrl-a '按编号或名字跳转
窗口Ctrl-a "弹出窗口列表供选择
窗口Ctrl-a A重命名当前窗口
窗口Ctrl-a k关闭当前窗口
窗口Ctrl-a w显示窗口列表(状态栏下方)
分屏Ctrl-a S水平切分
分屏Ctrl-a |垂直切分
分屏Ctrl-a Tab在区域间切换焦点
分屏Ctrl-a X关闭当前区域
分屏Ctrl-a Q只保留当前区域
复制Ctrl-a [或Ctrl-a Esc进入复制/回滚模式
复制Ctrl-a ]粘贴
复制Ctrl-a <space>设置选择标记
杂项Ctrl-a ?显示所有键位帮助
杂项Ctrl-a v显示版本
杂项Ctrl-a t显示时间与负载
杂项Ctrl-a l强制重绘屏幕
杂项Ctrl-a z临时挂起 screen,回到父 shell
杂项Ctrl-a :打开 screen 命令行
杂项Ctrl-a H开始/结束会话日志
杂项Ctrl-a M打开/关闭窗口活动监控
杂项Ctrl-a _打开/关闭静默监控

复制模式里还有一套独立的键位,第 6 章单独说,混在一起看容易乱。

5.2 一份抄了就能用的 .screenrc

配置文件放在$HOME/.screenrc。ZeroTermux 的 HOME 在应用私有区,用echo $HOME确认一下路径,然后直接编辑。

# 关闭启动时那个版权提示页 startup_message off # 回滚缓冲行数,默认只有 100 行,基本不够用 defscrollback 20000 # 关闭视觉响铃,手机上没有蜂鸣器但有震动反馈,没必要 vbell off # 脱离时自动 detach,避免会话被强杀 autodetach on # 打开 UTF-8 支持,中文不乱码的关键之一 defutf8 on # 状态栏:显示主机名、时间、窗口列表 caption always "%{= dk}%H %{= kw}|%{= dk} %l %{= kw}|%{-}%n %t%{= dk}%{= yk}%?%F%{= rk}%?%+w" # 把 screen 的内部 TERM 修正成 256 色版本 termcapinfo xterm* ti@:te@

几个参数值得单独解释。defscrollback是"新窗口默认的缓冲行数",设成 20000 意味着每个窗口能往上翻两万行。这个数值有内存代价,每个窗口按行宽乘以行数估算,20000 行在手机上大概是几 MB 的量级,开十几个窗口就要认真考虑了。我试过 50000,在低配设备上切换窗口有轻微卡顿,最后退回到 20000。

caption always那行如果报错或者界面错乱,直接删掉,不同发行版本对这个指令的支持不完全一致。删掉之后仍会有一行简单的状态栏,只是没那么好看。

改完配置想立刻生效,不用退出重开,在Ctrl-a :里输入source ~/.screenrc就行。这个技巧我用了很久才发现,之前每次都退出重建会话。

5.3 改前缀键之前想清楚代价

改前缀键的操作是在.screenrc里加一行:

# 把前缀改成 Ctrl-b escape ^Bb

注意格式是escape ^Bb,前面那个^B是新前缀(Ctrl-b),后面的b是新前缀按下后再按b时……这里的第二个字符其实是"prefix 键的替代键",通常写成跟第一个相同的小写字母就能工作,写成^Bb是常见惯例。

改之前想清楚两件事。一是肌肉记忆,你在桌面上用惯了Ctrl-a,换到手机上改掉,两边来回切的时候会疯。二是嵌套场景,Ctrl-b在某些程序里是"向上翻页",比Ctrl-a的冲突更常见。我的建议是除非Ctrl-a真的被吃掉了,否则别改。

如果只改一部分绑定、保留前缀,用bind指令更安全:

# 把 Ctrl-a 加 数字键 的跳转改成加 F 键 bind f screen -t log

bind的语法是bind 键名 命令,键名不带前缀。这个用法在给常用命令做快捷方式时很香,比如给"切到日志窗口"绑一个键,比记编号快。

6. 复制模式与回滚:日志看完再决定要不要留

6.1 复制模式的完整操作链路

screen 的复制模式不只是"复制粘贴",它同时是唯一的正经翻屏方式。滚动终端画面不是 screen 的功能,终端模拟器本身管自己的滚动,screen 一介入,滚动就被接管了,想往上翻必须进复制模式。

进入方式是Ctrl-a [或者Ctrl-a Esc。进去之后光标会跑到一个可以自由移动的位置,这时候整个回滚缓冲区都是可操作的。

移动光标的键位:方向键或者hjkl都行,0和$跳到行首行尾,g跳到缓冲区开头,G跳到末尾,Ctrl-b/Ctrl-f翻页,/向下搜索,?向上搜索,n找下一个匹配。搜索这个功能在翻长日志的时候特别有用,比一页页翻快太多。

选择文本的流程是:把光标移到起点,按空格,这一步没有视觉提示(有些版本会高亮),然后移动光标到终点,再按空格。两次空格之后,选中的内容被送进 paste buffer,同时自动退出复制模式。如果选错了想取消,按Esc退出。

粘贴是Ctrl-a ]。粘贴 buffer 里的内容可以用Ctrl-a :然后输入paste .也是同理。想清空 buffer 用:remove(会提示确认)或者:removep(删所有 buffer)。

6.2 缓冲区大小与内存:一个必须权衡的数字

前面提过defscrollback,这里展开说清楚代价。缓冲区的实现是每个窗口一份环形数组,行宽由终端宽度决定,行数就是配置值。粗略估算:80 列 × 20000 行 × 2 字节 ≈ 3.2MB,如果开了 UTF-8 宽字符,每行按双字节算也不止。加上 256 色终端每条行内嵌的转义序列开销,实际占用会更高。

在手机上这个量级不算大,但要配合窗口数量看。十个窗口全开 20000 行,就是三十多 MB,加上运行中的程序,低配设备上确实能感觉到。我的经验值是:设备内存 6GB 以上,20000 行随便设;4GB 及以下,压到 5000 行以内,靠搜索而不是靠翻。

另一个容易被忽略的点是,缓冲区是每个窗口独立的,不是每个会话共享。所以你在一个窗口里翻历史,翻不到另一个窗口的输出。这很合理,但新手容易困惑。

6.3 中文乱码与按键错乱的组合排查

这两个问题经常一起出现,根因往往是同一处:编码与 locale 不匹配。

先看现象。中文显示成问号或者方块,说明字符集没对上。退格键按下去屏幕上出现^H或者删不掉字符,说明终端控制序列的解释出了偏差。方向键变成^[[A这种裸转义序列,说明 terminfo 数据不匹配。

排查顺序我按照命中率从高到低排:

第一步,确认LANG环境变量。在 shell 里执行echo $LANG,如果输出为空或者C,中文基本没戏。临时方案是export LANG=en_US.UTF-8(或者系统里存在的某个 UTF-8 locale),写进.bashrc做成永久。ZeroTermux 环境里的可用 locale 有限,用locale -a看一遍,选存在的那个。

第二步,确认 screen 的 UTF-8 开关。在Ctrl-a :里输入utf8 on,看有没有提示。较新版本的 screen 用defutf8 on配置,运行时可以用Ctrl-a :试width之类看响应。如果版本不支持,可能需要更新 screen 本身。

第三步,确认不用 screen 的时候是否正常。脱离 screen 直接在 shell 里显示中文,如果也是乱码,问题在更上层,跟 screen 无关。这一步能快速定位责任方,我在手机上排查过两次,第一次以为是 screen 的问题,结果是 locale 压根没设。

按键错乱的处理稍微独立。方向键出裸序列,通常是TERM变量跟 terminfo 数据库对不上。screen 内部的 TERM 一般会设成screen或screen-256color,用echo $TERM看。如果是screen但系统里缺对应的 terminfo 条目,就会出现裸序列。修复方式是检查 terminfo 目录里有没有screen-256color,没有的话用infocmp导入一份,或者直接把 TERM 改成存在的类型。

退格键的问题更琐碎。有些程序期待退格发^H(ASCII 8),有些期待^?(ASCII 127)。可以在.screenrc里加bindkey -k kb stuff \177之类的映射来强制,但更简单的做法是在 shell 里用stty erase ^H临时试,有效再写进配置。这一块我没有统一的万能解,只能按具体程序的期待来调。

6.4 屏幕旋转之后画面错位

这是手机端独有的问题,桌面上遇不到。竖屏切成横屏,终端的可视区域变了,但 screen 内部记录的窗口尺寸不会自动更新,结果是画面上半部分是内容、下半部分是空白,或者状态栏飘到半中间。

处理方式是强制 screen 重新计算尺寸。较新版本有fit命令,在Ctrl-a :里输入fit之后回车,它会按当前终端尺寸重新布局所有窗口。如果没有fit,退而求其次,手动 resize:Ctrl-a :输入width 80之类的固定值,虽然死板但能救急。

还有一个更彻底的办法,配置里加一行让 screen 每次重绘时检查尺寸:

# 部分版本支持 rendition so = 7/5

这行的作用有限,真正可靠的是把fit绑到一个顺手的键。我绑了Ctrl-a f,旋转屏幕之后按一下,比临时敲命令行快。

多显示的场合要注意,fit只能让布局适配当前显示,如果另一个显示同时附加着,尺寸会取整到两者都能容纳的最小值,可能比你以为的小。这是设计使然,不是 bug。

7. 几个真踩过的坑,以及当时怎么绕出来的

7.1 前缀键在某个程序里"失灵"

有一段时间我在 screen 里用某个交互式工具,按Ctrl-a完全没反应,必须退出工具才能操作 screen。排查过程比较曲折,结论是这个工具自己也截获了Ctrl-a并做了绑定。

这类问题没有通用解,只能识别加规避。识别的方法是:在这个程序里按Ctrl-a再按?,如果弹出的是程序自己的帮助而不是 screen 的帮助,就确认被吃掉了。规避有两种,一是临时改前缀键(在这个会话里没法生效,因为前缀键是会话级配置),所以实际做法是进这个程序之前先把 screen 的前缀改掉,或者干脆接受限制,用Ctrl-a :之外的方式操作,比如直接开第二个窗口。

我最后的做法是给这个场景起一个专门的会话,启动时用-c参数指向另一份.screenrc,里面换成了Ctrl-b前缀:

screen -c ~/.screenrc-alt -S special

这份 alt 配置只有两行,改前缀加基础设置。这样两套配置并存,互不干扰。

7.2 reattach 之后画面花屏

杀掉应用重新进来,screen -d -r恢复,结果屏幕上是半截旧画面加半截新内容,光标位置也不对。这个现象在手机上出现频率明显高于桌面,原因是应用被杀之前终端没有正常发出尺寸变化通知,重连时新旧尺寸信息打架。

简单的解法是Ctrl-a l(小写 L),强制全屏重绘。这个键位处理过绝大多数花屏,包括那种字符错位一格的情况。

如果重绘无效,说明 screen 记录的尺寸严重偏离实际,用Ctrl-a :输入fit重新计算,或者Ctrl-a :输入width后面跟当前的实际列数、height跟实际行数。彻底的解法是退出这个会话重开,但那样窗口里的状态全丢,代价太大,我一般能修就修。

预防的角度,可以在配置里加autodetach on(已经加过了)和让应用在切后台前正常 detach。有些终端应用在失去焦点时会主动发 detach,有的话打开它,能省掉一半的花屏。

7.3 长任务跑到一半消失了

这个坑我踩得最深。现象是放着不管,一小时后回来看,screen -ls里会话还在,但里面的进程没了,窗口提示[1]+ Killed之类。

原因基本锁定在系统统一清理后台应用。screen 守护进程作为应用子进程,跟着一起被收走,但套接字状态没来得及同步,于是会话"看起来还在"。

当时的处置顺序:先确认是不是被清理,看系统的电池使用记录或者应用的后台活动日志,通常能看到被杀的时间点。然后做三件事,加入电池优化白名单、跑任务前申请唤醒锁、任务本身加断点续跑。

第三件最重要。我把长任务改成"每完成一个单元就写一次进度文件,重启时读进度文件跳过已完成的",配合 screen 之后,即使被清理,重启的代价也只是一分钟。这件事反过来说明一个道理:screen 减轻了中断的痛苦,但不能消除中断,把任务设计成可恢复,收益比折腾保活大得多。

7.4 同一个会话被两个地方追加,越用越乱

有次在分屏里忘了自己在哪个区域,两个区域其实是同一个窗口的两个显示,我以为是两个窗口,敲命令的时候看到输出重复出现两次,才反应过来。

现在我的做法是分屏之后立刻给每个区域确认窗口身份,用Ctrl-a i看当前窗口信息,或者看状态栏的窗口名。另外养成一个习惯:分屏时两个区域跑不同窗口,不要出现同一个窗口被两个区域显示的情况。真遇到了,Ctrl-a Q只留一个区域,问题立刻消失。

还有个小坑是Ctrl-a D(大写 D)。这个键是"从当前显示中 detach 而不影响其他显示",第一次按下去没反应,等了一会儿以为卡住,其实是进入了等待状态,要再按一次 D 或者选一个选项才生效。记不住就用小写d,语义清楚。

8. 我的实际使用习惯:最后几条经验

用到现在,我在手机上跑 screen 有一套固定的流程,写出来给同样在移动端折腾的人参考。

启动 ZeroTermux 之后第一件事是screen -d -r main,有就接上去,没有就报错,那我就screen -S main -t shell建一个。固定用一个主会话,窗口按用途分:shell敲命令,log挂日志,bg跑长任务。三个窗口足够覆盖九成场景,开得越多切换成本越高。

横屏的时候我会Ctrl-a S开分屏,一块看log一块操作shell,竖屏的时候关掉分屏,用Ctrl-a n来回切。这个切换过程本身很快,不需要犹豫。

翻日志一定用复制模式的搜索。Ctrl-a [进去,/加关键词,n一个个跳,找到了再决定要不要暂停任务去处理。比用手在屏幕上滑快得多,也准得多。

配置方面我只保留了第 5 章那份最小配置,多余的装饰性配置全都删了。曾经加过很花哨的状态栏样式,用了两周发现手机屏幕上那些颜色和符号反而增加认知负担,退回到最朴素的两段式。

最后一个小技巧:给自己常用的几个操作绑键。我的.screenrc里有这么两行:

bind l logfile flush 1 bind K kill -9

第一行让日志刷新更及时,第二行是强制杀进程的快捷方式(按Ctrl-a K然后按y确认)。这两个键位让我少敲了不少字。

真要说一句体会的话:screen 这类工具的价值不在于功能多强,而在于它把"进程活着"和"界面存在"这两件事解耦了。手机上界面消失是常态,把解耦做好,很多原本让人抓狂的中断就变得可以接受了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询