tmux attach -t build,画面连同上一条命令的输出一起回来,
那条命令一秒没停。
tmux,全称 terminal multiplexer(终端复用器):一个跑在终端里的常驻程序, 先在后台起一个一直在的 服务端 server,把程序放进 会话 session 里跑; 你面前这个终端窗口只是接上去看一眼的 客户端 client。一个会话里能开多个 窗口 window,一个窗口里还能再切成多个 面板 pane。 就像给每个要跑很久的程序租了一间不随你断线而消失的房间:你先走一步,它还在里面干活; 你随时推门回去,看到的还是离开时的那一屏,而不是一间空屋子。
你在终端里敲下的程序,是那个终端会话的子进程。
它的输入输出接在一根虚拟电话线上,术语叫 伪终端 pty(pseudo terminal):
线的一头是程序,另一头由终端模拟器或远程登录服务端(如 sshd)拿着。
SIGHUP(signal hangup,原意「电话线断了」);它的默认动作是终止,整组进程跟着退出。程序真正需要的,只是一根不会断的线;谁在看它、从几个窗口看它,本来是可以分开的两件事。
终端模拟器 / ssh 你面前的窗口与那条连接 -> 客户端 client 接上去看一眼的那一头 -> 服务端 server 一直在,替你看住会话 -> 会话 session 程序真正住的地方 -> 窗口 window 一屏能看的版面 -> 面板 pane 一屏再切出来的小块
SIGHUP
根本没送到程序耳朵里 —— 这是解决麻烦的关键一步。detach 是客户端退出,会话还留在服务端;
接回 attach 是另一个客户端接上同一个会话,所以两个窗口能同时看到同一幅画面。Ctrl-b),
再按一个字母表示动作;键位写在配置文件 ~/.tmux.conf 里,不改也能用默认值。/tmp/tmux-<uid>/default;
换个 socket 名就等于换了一个互不相见的服务端,一个账号可以跑多个独立实例。Ctrl-b;
这个组合在 vim、Emacs、readline 里各有原本含义,撞了就得把前缀键改成别的(如 Ctrl-a)或另设一套键表。ssh 到远端开第二个 tmux,前缀键就得按两遍
(或把触发方式改成双击);一旦记错层,键会被下面一层吃掉,屏幕上分不清自己身在何处。Shift 才能绕开它;想让鼠标听话要显式打开,想与系统剪贴板互通,通常还得另装一个中转程序。attach 进来,就能看到并操作
你正在做的事;而输出只活在会话里,想留档得自己再写一份进文件(如借助 tee)。场景一:在构建机上跑一次长编译,然后合上笔记本。
ssh build@10.0.0.5 # 先连上构建机
tmux new -s build # 开会话,名字叫 build
west build -b nrf52840dk/nrf52840 # 或 make -j8,要跑几十分钟
# 按 Ctrl-b 松开再按 d,客户端与本会话分离(detach)
# 之后合上笔记本、断网、关掉终端窗口,都不影响它
ssh build@10.0.0.5 # 第二天重新连上
tmux attach -t build # 接回同一个会话,输出还在原处
接回去看到的是同一个进程:它没被重启过,west build 的进度只是接着往下走。同一套做法也用在角落那台树莓派上:要跑的定时任务先 tmux new 起个会话,合上笔记本走人,第二天接回去看输出。
场景二:一次开几个服务,分屏看各自的日志。
tmux new -s logs # 开会话
vite # 面板 0 跑前端开发服务器
# Ctrl-b c 新开一个窗口,在里面跑:uvicorn app:app --reload
# Ctrl-b " 上下分屏(或用 Ctrl-b % 左右分屏),再起:docker compose logs -f backend
# Ctrl-b 方向键 在面板之间切换;Ctrl-b z 把当前面板临时放大,再按一次还原
每路日志各占一块,谁在刷屏一眼看得出;要回滚翻看,按 Ctrl-b [ 进入翻阅模式,再按 q 返回。
不用开三四个终端标签来回切,也不怕哪个标签被误关。
先问一句:关掉这个终端窗口,里面的程序还活不活?活着,背后就有东西在托管它。 再问一句:这句话说的是哪一层?
| 名词 | 它是什么 | 和 tmux 什么关系 |
|---|---|---|
| tmux(终端复用器) | 跑在终端里的常驻服务端,加上能随时接回的会话 | 本课主角,管的是「程序活得比这一次连接久」 |
| GNU screen | 同族里更早的终端复用器,同样能分离、接回、分屏 | 同类替代品:能力重叠,配置与插件生态不如 tmux 齐整 |
| nohup | 一条命令:让被它启动的那个程序忽略 SIGHUP(内核在连接断开时发给进程的退出通知) |
只做「别被打断」这一半 —— 它不给你能接回去的界面,断线后看不见也回不去;想接回去得用 tmux |
| disown | Shell 内置命令:把已经在跑的任务从 Shell 的任务表里摘掉 | 和 nohup 同一边:不提供界面,输出还挂在原来那根终端上 |
| 终端模拟器(如 Windows Terminal) | 把字画上屏幕、把键盘送进去的那个窗口程序 | 上下两层:tmux 跑在它里面;窗口一关,没被托管的程序照样死 |
| SSH(secure shell,安全外壳) | 把远端一个 Shell 接到本地来的加密连接 | 通常就是 tmux 的上一层;这条路一断就没了,让远端进程活下来的是 tmux |
| systemd 服务 | 开机自动拉起、崩了自动重启的常驻程序 | 补上 tmux 管不到的那一段(跨机器重启),代价是没有可交互的界面 |
一句话分工:终端模拟器管「画」,SSH 管「连」,Shell 管「解释」,复用器管「活得比连接久」。
attach
只是新开一个客户端接上去,所以输出是接着出现的,不是从头再来。nohup 的升级版。」错在把两件事当一件:nohup 只改了一个信号的默认处理,
复用器额外给了你一层能回看的界面;只要「别死」、不要「回看」,nohup 就够。三题自测,每题只有一个正确选项;选完立刻看到解释。
1. 关掉本地终端后,里面的程序还能继续跑,靠的是什么?
对。程序抓着的那根伪终端不在你手里,而在常驻服务端手里;你断开的只是「客户端到服务端」这一段,那声 SIGHUP 根本没送到程序耳朵里。
2. 把字画到屏幕上、把键盘送进去的那个窗口程序,叫什么?
对。终端模拟器管「在哪儿看」(窗口、渲染、键盘),复用器管「活得比连接久」(托管会话与窗口);是上下两层,不是同一件事的两种叫法。
3. 下面哪种情况,会把住在服务端里的会话一起带走?
对。会话都住在服务端进程里,重启会把服务端一起带走 —— 跨重启要交给系统服务管理器或外部快照工具,那已经出了复用器的范围。