‹ 指南

手机上这样用 tmux,顺手很多

手机只有一块屏幕,也没有窗口管理器。tmux 让你在一条连接里开出好几个,而键盘上方那排按键会自己变成 tmux 那一套。

撰写于 · 更新于

一条连接,多个窗口

电脑上你习惯并排开三四个终端窗口,但手机做不到:只有一块屏幕,而且不大。看起来最顺手的办法是在 Term 里多开几个标签页,但这有个问题:每个标签页都是另一条连接,而连接恰恰就是手机锁屏、或者你在别的应用里待久了之后会断掉的东西。

tmux 的窗口才是答案:一条连接、一个会话,里面想开几个窗口就开几个。一个跑构建,一个看日志,一个开编辑器。切换只要一下,切走了也没有任何东西会停。^Bc 新建窗口,^Bn 和 ^Bp 前后切换,^Bw 打开列表直接挑。这三个都在键盘上方那排按键里,横向滑动就能找到。

手机上运行 tmux:日志在滚动,tmux 状态栏写着 work | 1:build 2:logs 3:edit,下面的按键栏是 ^B[ ^Bz ^Bc ^Bn ^Bp ^B%。
屏幕最下面那条是 tmux 自己的状态栏,也是这张地图:work 是会话名,然后是 1:build 2:logs 3:edit,正在看的那个带 *。再下面一排是 Term 的按键栏,已经换成 tmux 那一套了。
tmux 的窗口列表覆盖在会话上,列出三个窗口,其中一个高亮。
^Bw:窗口列表。窗口多到不想一个个翻的时候用它,选中哪个就进哪个。
按键栏会自己换

tmux 那套键不用你去开。Term 会看你前台在跑什么,然后把键盘上方那一排换成对应的:开了 tmux 就换成 tmux 的,退出来就换回去。它能知道,是因为你的 shell 会告诉它,也就是设置里的「Shell 集成」,默认开着。同一条信息在顶部导航栏也看得到:待在会话里的时候,那里写的是 tmux attach -t work。

ctrlaltshifttab esc^B↑↓←→ ^B[^Bz^Bc^Bn^Bp ^B%^B"^Bo^Bw^Bd ^C^R

按键上的字是故意把整个组合拼出来的。一个标着 | 的键看上去像是打一个竖线,但它不是,它是分屏。^B% 不会被看错,而且它顺便教会了你真正的按法,这个按法在你自己电脑上是一样的。很多人第一次接触 tmux 就是在手机上,手边没有速查表,这排按键就是速查表。不在这排里的键,点最左边的 ctrl 再按字母:它会给下一个按键挂上 Ctrl,alt 和 shift 同理。

一张图里同时有:tmux 打出的「[detached (from session work)]」,以及下面已经换回普通 shell 那一套的按键栏。
一张图看清这次切换:^Bd 脱离的那一刻,tmux 打出 [detached (from session work)],下面那排按键已经换回 shell 的了。这中间不需要你配置任何东西。
分屏,以及为什么「放大」在这里更重要

分屏切的是你当前这个窗口:^B% 把新窗格放在旁边,^B" 放在下面。然后手机就开始碍事了。默认字号下 Term 给你 56 列,左右分屏之后一边 28 列、一边 27 列,一条普通的日志或者编译报错,还没说到重点就已经折了两行。

手机上一个 tmux 窗口左右分成两个窗格,每个约 28 列宽,两边的文字都在词中间折行。
一边 28 列。两个窗格都工作得好好的,只是宽度不够让任何一边读着舒服。读不了的分屏,等于没分。

^Bz 就是解法,而且它在手机上的价值远高于在电脑上。它把你所在的窗格放大到整个窗口,同时布局原封不动,看完想看的,再按一次,分屏还是刚才那个分屏。手机上比较顺手的用法是:需要来回切的用窗口,真的要同时盯着两样东西才用分屏,并且让其中一个保持放大。^Bo 切到下一个窗格,^B 之后接方向键则按方向切。

同一个分屏,其中一个窗格放大到整屏,状态栏窗口名旁边多了一个 Z。
同一个分屏,放大之后。这个窗格拿回了完整的 56 列。状态栏窗口名旁边那个 Z,就是「这是放大的窗格」和「这个窗口本来就只有一个窗格」的区别。
回滚历史 = 复制模式

进了 tmux 之后,拖动屏幕不再是滚动终端,屏幕归 tmux 管了。它的历史在复制模式里,^B[ 是入口;进去之后拖动即可滚动,也可以用按键栏上的方向键,esc 退出。

这一点在 mosh 上最要紧:mosh 传的是当前这一屏,不是一行行的字节流,所以它本身没有历史可供 Term 回滚,这是 mosh 的设计,不是应用的限制。在里面跑 tmux,复制模式就是你的回滚区,能翻多远由 history-limit 决定。

tmux 会话处于复制模式并已向上回滚,右上角显示 [100/132]。
复制模式,角上那个计数就是你的位置:[100/132] 表示在一共 132 行的历史里往回翻了 100 行。
脱离与挂回

^Bd 脱离。你正在跑的东西全都留在服务器上继续跑(构建、日志、编辑器里还没存的内容),之后 tmux attach -t work 把整个会话原样接回来:一样的窗口、一样的分屏、一样的滚动位置。懒得记会话建没建过的话,tmux new -A -s main 有就挂上、没有就新建,很适合直接写进主机的启动脚本。

这正是 tmux 在手机上值得折腾的原因。切到后台后 Term 能撑住大约 70 秒,之后 HarmonyOS 就会挂起应用,连接也随之关闭。但只要另一头有 tmux,这一下什么都不会损失:你只是脱离了,不是被中断了。

挂回之后的会话:还是那个分屏,日志仍在滚动。
挂回来了:还是那个分屏,日志还在跑,滚动位置也留着。会话这一侧根本没察觉手机离开过。
关于 mosh 的一点说明

走 SSH 的时候,Term 是靠 shell 上报的命令知道你前台在跑什么的。mosh 会话不会以同样的方式上报命令,所以如果你用 mosh 连上去,再自己敲 tmux attach,会话本身跑得好好的,但按键栏会停在 shell 那一套。ctrl 仍然可用,ctrl 再 b 再字母一样能发出去,只是没法一键完成。

通过 mosh 连上的一个真实 tmux 会话,下面却是普通的 shell 按键栏,不是 tmux 那一套。
mosh 里的 tmux,配的是 shell 键。会话是真的(状态栏和窗口名都在),但下面这排是 shell 的。下面两种办法都只要改一行。

让主机替你启动 tmux

在主机的启动脚本里写上 tmux new -A -s main。Term 会把启动脚本一并算进它对这个会话的判断里,于是从第一帧开始就是 tmux 那排键,而且你一连上去就已经在会话里了,不用再自己敲进去。

或者,把那个词放进标题

Term 也会读终端标题,只要标题里任何位置出现 tmux 这个词就算数。下面那份配置里写的是 set-titles-string "#{pane_title}",得到的标题是 build 这样的:里面没有 tmux 可找。改成 set-titles-string "tmux · #{pane_title}",不用动主机设置,mosh 下也能拿回 tmux 那排键。

这份应用实际用来测试的 tmux.conf:我们在用的 tmux 配置 · 常见问题:mosh + 复用器