Tmux 入门教程

陪她去流浪 桃子 2020年05月17日 阅读次数:3513

在学习 tmux 之前,我觉得 iTerm2 已经足够用了。

在学会 tmux 之后,我完全彻底地改变了这种看法。

注:这篇文章很长,并且在更新中。我希望你能耐心地读完,并且一次性学会 Tmux 的日常使用。有任何问题,请评论。

Terminal 与 iTerm2

在介绍 “后浪” tmux 之前,先介绍一下它的 “前辈” 们。

Mac OS 自带的终端模拟器 Terminal(终端),只能一个窗口打开一个终端。要想打开多个窗口,需要运行多个 Terminal。窗口之间相互独立。这使得在窗口之间切换时并不方便。用过 IE 6 吧?

后来出现了 iTerm2,相比于 Terminal 来说,iTerm2 支持了标签页(TAB)。Terminal 和 iTerm2 在这方面的比较,就像是 IE 6 与 Chrome 的区别。 除此之外,iTerm2 还支持一个窗口(Window)拆分成多个窗格(Pane)。这比 Terminal 好用了很多。这些都是刚需。

不论是 Terminal 的窗口多开、还是 iTerm2 的多个标签页或窗格拆分,它们新产生的终端都是利用的是你正在使用的操作系统的 GUI 图形功能实现的,即打开的是另一个几乎完全独立的一个终端。 比如:一个窗口 ssh 到了服务器,如果此时新开一个窗口(或标签或窗格),你需要再次 ssh,才能到达服务器。

所以, tmux 有何不同?

Tmux 介绍

Tmux (terminal multiplexer) 是一款终端多路复用(Multiplexer)软件。

与前面提到的几款终端模拟器最大的不同之处在于:

它是一款命令行软件,它的多窗口、多窗格模式是在 CUI 模式下实现的。

这意味着,你可以只打开一个终端,然后在里面不停地用 tmux 打开新的窗口、窗格等。而如果你的 tmux 是 ssh 到服务器之后在服务器上运行的,你将拥有在服务器在打开多个窗口、多个窗格的能力。 这样一来,你就不必多次 ssh 到同一台服务器上,只为执行不同的命令了。而且还不用担心断网,因为可以重连。

Tmux 还拥有非常强大的命令及快捷键系统,跟 Vim 类似。

是不是很优秀? 想不想学?

几个概念

在继续介绍之前,首先介绍 tmux 的几个名词。从小到大依次介绍:

  • 窗格(Pane)

    一个窗格即一个真正的独立的终端界面,它起始于用户的 shell。就像是你新打开了一个 Terminal。

  • 窗口(Window)

    一个窗口包含多个窗格,也可以说是一个窗口被拆分成了多个窗格。 记得 Windows 操作系统的图标吗?1 个窗口被分成了 4 个窗格。 就像是你在 iTerm2 内把一个窗口拆分成多个窗格一样。

    一个窗口(内的所有窗格)将占据整个屏幕。

    也可以按最大化快捷键,将当前活跃的窗格最大化,此时该窗格将占据整个窗口。

  • 会话(Session)

    一个会话包含多个窗口。由于一个窗口即占据整个屏幕,所以需要按快捷键在不同的窗口之间切换才能显示其它的窗口。

    客户端每次只连接到一个会话,但是可以在会话之间切换。

  • 服务器/标签(Label)

    这里的标签的含义是给 tmux 服务器取一个名字。一个标签即一个服务器。

    一个服务器管理多个会话。

    默认运行时,标签名字叫“default”,路径为:/tmp/tmux-<uid>/default

    其实很少有启动不同 tmux 服务器的需要,我们通常做的是创建不同的会话、不同的窗口、不同的窗格。测试是一个例外。

  • 用户(User)

    不同的系统登录用户之间运行的 tmux 服务器当然应是隔离的。文件系统路径:/tmp/tmux-<uid>/

概念似乎挺多,但其实非常好理解。我们反过来再理解一下。

  • 一个系统可以登录多个用户
  • 一个用户可以启动多个标签
  • 一个标签可以包含多个会话
  • 一个会话可以打开多个窗口
  • 一个窗口可以拆成多个窗格

是不是很好理解了?

当然,一个窗格就是最原始的 shell。你可以在里面再次运行 tmux,天呐…… Tmux 默认不允许这样做 :-)

非常实用的特性

Tmux 有哪些与众不同、出类拔萃的功能?

  • 多窗口、多窗格功能在终端内实现

    只需要打开一个终端模拟器窗口或一个 ssh 会话,即可实现多窗口、多窗格。

  • 从会话分离、重新连接会话

    从会话分离,意味着回到原始的 shell 提示符。重新连接到会话,意味着从命令提示符重新进入 tmux 实现的多窗口、多窗格界面。 这种行为就像你在最小化和还原一个图形窗口一样。

    所以你不必再把你要运行的命令放到后台执行了,你只需要把 tmux 最小化即可(分离会话)。

    这个能力的实现,得益于 tmux 的 客户端/服务端(C/S) 模型。

  • 不受 网络连接/ssh 断开的影响

    当直接在 ssh 后的 shell 里面执行命令时,如果此时 ssh 连接不小心断开,你就再也无法回到连接断开前的界面了。正在执行的命令可能也会立即退出。 而 tmux 不一样。断开连接其实就是上述“从会话分离”。ssh 断开后,重新 ssh 到服务器,再“重新连接会话”即可回到连接断开前的 tmux。

    这一点超级实用!再也不用担心网络连接突然异常断开了。

  • 多个客户端可以连接到一个会话

    多个客户端连接到同一个会话,可以让它们显示完全一样的内容。但是客户端的显示区域大小不一样怎么办?会以最小的客户端大小重新调整大小。

  • 方便地在窗口、会话之间切换

  • 非常强大的命令及快捷键系统

    Tmux 的各种能力通过命令来完成,而且绝大多数命令可以绑定到快捷键来完成复杂的工作。

    关于 Tmux 的命令及快捷键,将会在后面独立的章节介绍。

Tmux 的实用特性远不止这么多,还需要耐心挖掘。

状态栏

状态栏默认位于屏幕底部,用于显示:当前会话名,当前会话的窗口列表,当前的主机名及时间(可自定义)。

注意,状态栏是 tmux 的一个非常明显的标识。绿色的一长条,位于屏幕底部。

一个正在运行的 tmux 截图

注:在移动设备下,可能显示错乱。

version: "2" 1 package main

services: 1

nginx: 2 // Path ...

image: nginx:1.17.8 3 type Path struct {

container_name: nginx 4 > Name string `yaml:"name"`

network_mode: host 5 > Token string `yaml:"token"`

volumes: 6 > Local string `yaml:"local"`

- ./conf:/etc/nginx:ro 7 > Remote string `yaml:"remote"`

- ./html:/usr/share/nginx/html:ro 8 }

- ./logs:/var/log/nginx 9

- ..:/etc/nginx/servers:ro 10 // Config ...

restart: unless-stopped 11 type Config struct {

12 > Listen string `yaml:"listen"`

root@twofei:~/servers/nginx# │<tcp/config.go" 18L, 358C 1,1 Top

─────────────────────────────────────────────┼────────────────────────────────────────────

Active Internet connections (only servers) Filesystem Size Used Avail Use% Mounte

Proto Recv-Q Send-Q Local Address Fudev 345M 0 345M 0% /dev

tcp 0 0 127.0.0.1:2563 0tmpfs 74M 7.5M 66M 11% /run

tcp 0 0 127.0.0.1:2564 0/dev/vda1 34G 8.7G 24G 28% /

tcp 0 0 127.0.0.1:3306 0tmpfs 367M 0 367M 0% /dev/s

tcp 0 0 0.0.0.0:80 0tmpfs 5.0M 0 5.0M 0% /run/l

tcp 0 0 127.0.0.1:3826 0tmpfs 367M 0 367M 0% /sys/f

tcp 0 0 127.0.0.1:8021 0tmpfs 74M 0 74M 0% /run/u

tcp 0 0 0.0.0.0:22 0overlay 34G 8.7G 24G 28% /var/l

tcp 0 0 0.0.0.0:443 0shm 64M 0 64M 0% /var/l

tcp 0 0 127.0.0.1:40479 0overlay 34G 8.7G 24G 28% /var/l

tcp6 0 0 :::22 :shm 64M 0 64M 0% /var/l

tcp6 0 0 :::8443 :overlay 34G 8.7G 24G 28% /var/l

: :

[twofei] 1:proxy 2:mysql 3:blog 4:nginx 5:taolang 6:play* 7:http2tcp- 01:20

Tmux 的命令系统及基本使用

Tmux 毕竟是一款命令行软件,所以用命令来完成各种任务再适合不过了。

基本语法:

$ tmux [命令] [选项]

下面介绍的基于命令的用法只是让你能快速掌握 tmux 的基本用法。命令式的操作比起快捷键来说要麻烦得多,但是鉴于我们还没学习快捷键,所以暂且如此。

新建会话

在 shell 内执行 tmux 即可。此时没有提供 [命令][选项],默认为 tmux new-session,即创建新的会话。

在执行此命令时,若 tmux 发现当前用户没有启动服务器,则会创建一个名为“default”的服务器,然后才创建一个会话。

新的会话创建好之后,同时会创建一个新的窗口,这个窗口包含一个窗格。

大多数时候我们只关心“会话”、“窗口”、及“窗格”。我们很少创建多个服务器。

示例图(没有展示颜色):

注:我的命令提示符是当前目录后面跟一个向右的箭头。并且我的 tmux 是配置过的,如果你还没有创建过 tmux 配置文件,显示可能稍有区别。

~ →























[1]                                 1:bash*                                17:14

提示:new 命令是 new-session 的别名,可以代替使用。

拆分窗口为窗格

拆分可以水平拆,也可以竖直拆。

  • 竖直拆分:tmux split-window
  • 水平拆分:tmux split-window -h

以下是我一次竖直拆分、一次水平拆分后的结果:

~ → tmux split-window
~ → 










────────────────────────────────────────┬───────────────────────────────────────
~ → tmux split-window -h                │~ →
~ →                                     │
                                        │
                                        │
                                        │
                                        │
                                        │
                                        │
                                        │
                                        │
                                        │
[6]                                 1:bash*                                17:22

可以看到,一个窗口首先因为竖直拆分被拆分成了上下两个窗格,然后由于水平拆分,下面的窗格再次被拆分成了两个窗格。

在窗格之间切换

每次只有一个窗格处理“选中(活跃)”状态,所以需要切换使用的窗格。

默认设置下,Tmux 是未打开鼠标支持的,并且我们还没有讲解到如何用快捷键切换,所以暂时用命令来完成吧。

  • 选择左边的窗格:tmux select-pane -L,L 即 Left;
  • 选择右边的窗格:tmux select-pane -R,R 即 Right;
  • 选择上边的窗格:tmux select-pane -U,U 即 Up;
  • 选择下边的窗格:tmux select-pane -D,D 即 Down;

当前活跃的窗格的边界会以绿色显示出来,注意观察。

窗格最大化与还原

命令:tmux resize-pane -Z

第一次执行时,当前窗格将占据整个窗口(即最大化)。再次执行后,将还原。

此时状态栏的当前窗口名(带“*”的)后面将会显示一个“Z”字符,表示 Zoomed,即最大化了。

这在窗格太多,显示区域太小的时候非常有用。

将窗格独立到新窗口

命令:tmux break-pane

除了上述的最大化窗格,还可以用这个把窗格独立到新窗口。

新建窗口

窗格拆得太多会很越来越小,此时可以新建窗口以完成其它的任务。

命令:tmux new-window

~ →























[6]                             1:bash- 2:bash*                            17:38

窗口列表在底部状态栏显示着,当前的窗口名后面带一个*号。上一次的窗口名后面带一个-号。

这个窗口跟最开始的窗口无异。拆分窗格你随意进行就好。

切换窗口

在一个窗口内切换窗格刚刚已经学会了,现在来学如何切换窗口。

命令:tmux select-window -t :=<窗口编号>,看起来有点长。

每个窗口都有一个数字编号,位于底部状态栏窗口列表中每个窗口名的前面。

比如,要选择窗口 2:tmux select-window -t :=2

Tmux 最小化与还原

Tmux 最小化即前面提到的客户端:“会话分离”、“会话重连”。

  • 会话分离:tmux detach-client(相当于最小化)
  • 会话重连:tmux attach-session(相当于还原)

在最小化之后,你就可以回到最初的 shell 命令行了。这有点类似于按 C-z 把 vim 最小化,然后 fg 将其还原。

不管 tmux 有没有最小化,你都可以非常安全地断开 ssh 连接,或者关闭终端模拟器。然后在重新打开终端或ssh后重连会话回到 tmux。这在前面已经介绍过。

注意:client 与 session 可以简单看作是同一个概念,因为一个 client 连接到一个 session。不必过分纠结。

提示:aattach-session 的别名,可以代替使用。

切换会话

切换会话之前,你应该知道当前有哪些会话列表:

当前会话列表:tmux list-sessions

示例输出:

$ tmux list-sessions
0: 2 windows (created Wed May 13 01:46:44 2020)
6: 2 windows (created Sun May 17 17:21:59 2020)
7: 1 windows (created Sun May 17 17:56:32 2020) (attached)

行首的数字是会话的名字,因为是自动生成的,所以看起来没啥辨识度,后面会讲到更名。

然后记得前面的数字,执行以下命令切换过去:

切换到会话:tmux switch-client -t <会话名>

这个过程看起来挺繁琐的,事实上的确如此。所以,有一个更好的交互式命令用来快速切换会话:

交互式切换会话:tmux choose-tree -sZ,s 表示 session,Z 表示 zoomed。

下面是示例图:

(0)  + 0: 2 windows (attached)
(1)  + 6: 2 windows
(2)  + 7: 1 windows









┌ 0 (sort: index)──────────────────────────────────────────────────────────────┐
│ t interactive shell is now zsh.      │2020/05/16 05:11:33 accept: 127.0.0.1: │
│ your account to use zsh, please run `│2020/05/16 05:14:19 accept: 127.0.0.1: │
│ etails, please visit https://support.│2020/05/16 17:02:08 accept: 127.0.0.1: │
│ plit-window                          │2020/05/16 17:05:02 accept: 127.0.0.1: │
│               ┌───────┐              │2020/05/16 17┌──────────┐t: 127.0.0.1: │
│               │ 1:vim │              │2020/05/16 21│ 2:[tmux] │t: 127.0.0.1: │
│               └───────┘              │2020/05/17 04└──────────┘t: 127.0.0.1: │
│                                      │2020/05/17 04:57:38 accept: 127.0.0.1: │
│                                      │2020/05/17 17:58:03 accept: 127.0.0.1: │
│                                      │                                       │
└──────────────────────────────────────────────────────────────────────────────┘
[0]                            1:vim- 2:[tmux]*                            18:08

窗口上半部分展示了一颗“树”:首先是会话列表,然后展开后是会话内包含的窗口列表,再然后是窗口内包含的窗格列表。

窗口下半部分是会话、窗口、窗格的预览图。

你可以使用方向键(如果你会 vim,可以用 hjkl)上下切换或开展与折叠,导航到你想要去的会话、窗口或窗格时,按下回车即可切换过去。

给会话及窗口命名

默认的会话是以数字递增命名的,基本没有辨识度。所以我们应当重命名它。

命名会话:tmux rename-session <会话名>

以下是示例,注意左下角的变化:

~ → tmux rename-session 这是一个会话名
~ →






















[这是一个会话名]                       1:bash* 2:bash-                     18:17

当然,切换会话的时候就有辨识度了:

(0)  + 0: 2 windows
(1)  + 7: 1 windows
(2)  + 这是一个会话名: 2 windows (attached)





















[这是一个会话名]                     1:[tmux]*Z 2:bash-                    18:18

重命名窗口也很类似:

命名窗口:tmux rename-window <窗口名>

~ → tmux rename-window 窗口名
~ →






















[这是一个会话名]                      1:窗口名* 2:bash-                    18:20

注意到底部的窗口名的变化。

切换会话时:

(0)  + 0: 2 windows
(1)  + 7: 1 windows
(2)  - 这是一个会话名: 2 windows (attached)
(3)  ├─> - 1: 窗口名*Z (3 panes)
(4)  │   ├─> 0: bash "MacBookPro-Home.local"
(5)  │   ├─> 1: bash "MacBookPro-Home.local"
(6)  │   └─> 2: bash "MacBookPro-Home.local"
(7)  └─>   2: bash- (1 panes) "MacBookPro-Home.local"
















[这是一个会话名]                     1:窗口名*Z 2:bash-                    18:21

快捷键系统

你会 Vim 或 Emacs 吗?这两者都有着非常强大的快捷键系统。 Vim 被很多人用来修改配置文件,熟悉的人挺多。Emacs 呢?正如我在 Bash 终端常用快捷键总结 提到的那样,你在编辑命令时,那些常用的 C-aC-e 其实就是 Emacs 的快捷键呢。

Tmux 也有着与它们类似的复杂的快捷键系统。老实说,短时间内要记住它们挺难的,还需要多操练。有没有被吓到?

Vim 有 Leader 键,Tmux 有 Prefix 键。Prefix 键拿来干啥?

因为默认情况下,你在窗格内进行的应该是命令编辑操作,就像你在普通的终端那里敲字符编辑并执行命令一样。 所以为了不让普通的字符有特殊的功能,应该在按下字符前加一个 Prefix,即前缀。

Tmux 默认的 Prefix 键是 C-b,即 Ctrl-b。 按下 Prefix 之后,就可以再输入一个字符即可完成快捷键的录入。

多数常用的命令都会以 Prefix 开始。 比如:C-b c,即先按下 Ctrl-b,再按下 c。可以创建一个新的窗口。

默认的 Prefix 快捷键列表

以下是部分常用的默认 Prefix 快捷键列表(记得先按 Prefix 键):

?           显示所有的快捷键(不止是 Prefix 表中的,后面会介绍)
c           新建窗口
"           竖直拆分当前窗格为上下两个
%           水平拆分当前窗格为左右两个
!           把当前窗格拆分到新窗口
z           最大化窗格与还原
$           重命名当前会话
,           重命名当前窗口
s           交互式选择会话、窗口、窗格
d           分离会话
0 to 9      选择编号为 0-9 之一的窗口
=           浏览剪贴板列表,回车粘贴
:           进入命令末行模式(似 vim),此时可以输入命令,不用带最前面的 tmux
r           重绘 tmux 窗口(有时候不小心清屏了可以用这个显示出来)
t           显示当前时间
]           进入拷贝模式
方向键       切换窗格

如何发送 Prefix 键给原来的进程?

C-b 在 shell 里面默认是光标回退一个字符(详见:Bash 终端常用快捷键总结),但是被 tmux 截获并作为了 Prefix 键。C-b 不能再提供原来的功能了。

怎么办? 很简单,按两次即可,即:C-b C-b。默认情况下这个快捷键就提供了。

进入末行命令模式

有时候正在运行一个全屏的程序,要回到 shell 并执行一个 tmux 命令 并不友好。所以,末行模式可以暂时用来完成命令的执行。

进入末行命令模式(类似 vim):Prefix + :,你应该知道怎么输入冒号吧?冒号在分号的上面,需要按 Shift + ; 输入。

进入后,底部状态栏会有一个命令提示符,你就可以输入并执行命令了。由于是在 tmux 环境内执行的,你不用再输入命令开始的 tmux

快捷键的分表

Tmux 的快捷键分布在不同的“表”中,前面提到的 Prefix 表是其一。在 Prefix 表中的快捷键,需要先按下 Prefix。

除 Prefix 表以外,还有 root 表,copy-mode 表等。在 root 表中的快捷键不需要像在 Prefix 表中的快捷键那样需要先按一个前缀,而是直接按下即可。

比如,你可以自定义绑定c为创建新窗口,然后,简单地按下c就可以创建新窗口了,而不需要再先按下像是 Prefix 那样的组合键。 但是,正如前面所说,默认情况下,你应该是在编辑将要被执行的命令,而不是按下快捷键,所以,root 表用得并不是特别多。绑定在 root 表中的快捷键也并不多。 当然,也并不是没有用。后面讲解“鼠标支持”的时候会看到实用功能。

copy-mode 表是什么表?终端通常会有很多输出(来自 stdout 和 stderr),特别是当有大量输出时,非常不利于我们复制终端内的内容。 所以,正如其名字所代表的,这个表是 copy-mode(拷贝模式)下所要用到的表。所以,什么是“拷贝模式”?后面再详述。

快捷键的绑定与取消

默认快捷键其实挺好的,但毕竟众口难调,操作习惯也不一样。所以,自定义快捷键的绑定与取消是很实用的。

快捷键独立于表的,所以要绑定快捷键,就要事先说明绑定在哪个表中。

  • 绑定快捷键语法:bind -T <表名> <按键> <命令>
  • 解绑快捷键语法:unbind -T <表名> <按键>

注意:我没有再在前面加 tmux 前缀了,你自己应该知道什么时候应该加了吧?<命令>处也不用加tmux

提示:

  • 不指定表名时,默认绑定到 Prefix 表
  • bind -n 等价于 bind -T root(n 即 normal)
  • bind -r 表示这个快捷键可以重复执行(r 即 repeatable)

示例:

# 绑定按 c 直接创建窗口
bind   -n c new-window

# 解绑按 c 直接创建窗口
unbind -n c

# 绑定按 Prefix Esc 为隐藏状态栏
bind Escape set status

对于我等 vim 党不喜欢方向键的人来说,用 h/j/k/l 来代替 左/下/上/右 是太正常的事了:

bind -r h select-pane -L
bind -r j select-pane -D
bind -r k select-pane -U
bind -r l select-pane -R

听说 HHKB 机械键盘 没有 方向键?Oh my god!我是一定不会用的,一点都不香。(其实主要是穷)

我本人并不建议使用 tmux 的初期就修改 Prefix 键(马上说)和绑定太多键。因为:对于像我这种经常登录到公司的各种服务器上的人来说,我可没精力把配置文件全部同步到每台服务器上。 所以,熟悉默认按键总是好的,不会一时忘了套。

另,我应该会写一篇新的文章来贴出我的 tmux 配置(我觉得真的挺好用的)。如果没有,就当我没说,你也没看到。

自定义 Prefix 键

打脸,刚刚说了不应该一开始就修改按键绑定,立马就修改了。。

正如前面所提及的,C-b 在 shell 里面是使光标向左移动一个字符的(我可不喜欢方向键,手的移动跨度太大了),我用得很频繁。所以需要修改一下默认的 Prefix 键。

改成什么键好呢?我参考了我几个同事以及网友的:

  • C-a,这跟 C-b 没差啊,C-a 是回到命令行的行首。大量使用的快捷键为什么要被替换掉;
  • C-o,这是 vim 的在 Insert 模式下临时切换到 Normal 模式的快捷键啊,你怎么老是跟我作对?;

后来我选了 C-jC-j 在 shell 里面相当于按下回车,好像没啥用处。那就这样吧。

注意:修改 Prefix 是通过 set 命令来完成的。

# 默认的 Prefix 键
set -g prefix C-j

# 两次按下 Prefix 发送 Prefix 给原来的进程
bind C-j send-prefix

# 取消原来的 Prefix 绑定
unbind C-b

鼠标支持

在没有开始鼠标支持时,不能用鼠标来滚动历史内容、不能用鼠标来切换窗格、不能用鼠标来改变窗格的大小。挺不方便的。 并且,滚动鼠标滚轮居然默认是滚动历史命令,而不是历史内容,谁能忍???

新版本(不是太老即可)的 tmux 已经能一键开启鼠标支持了。命令如下:

set -g mouse on

拷贝模式

在拷贝模式下,屏幕会暂停更新,并且有一张新的快捷键表。这时候可以通过鼠标来选择文字进行复制。

拷贝模式的快捷键默认是 Emacs 风格的,不熟悉,改成 vim 应该会熟悉很多。

# 拷贝模式使用 vim 风格的快捷键
set -wg mode-keys vi

# 解绑原来的所有 emacs 快捷键
unbind -a -T copy-mode

进入拷贝模式的方式:Prefix ]

如果开启了鼠标支持,则回滚历史、鼠标选择文本默认都会自动进入拷贝模式。

在 vim 拷贝模式下,大部分 vim 类似的滚屏,光标移动都是可以使用的。 另外有一些特殊的:

  • Space 进入文字选择模式
  • Escape 清除选中文字

暂时先写这么多吧,几个小时了,好饿。。。

这篇文章的内容已被作者标记为“过时”/“需要更新”/“不具参考意义”。

标签:tmux