玩转Linux Shell & Terminal & Tmux

一、Shell编程☘️

1. Shell指令快捷操作

1. echo
# 系统指令
$ echo $(pwd) # 对于系统自带的pwd,此处不能写echo $pwd

# 自定义变量
$ foo=$(pwd)
$ echo $foo   # 不同于pwd,对于自定义的foo,不能用$(foo)
2. !!
# 假设你先执行了以下原本需要权限的指令
$ mkdir /mnt/xuyang
# 终端立即提示你:Permission denied,这时可通过如下指令进行简化:【!!默认指代上次指令内容】
$ sudo !!  # 该句等效于:sudo mkdir /mnt/xuyang
3. rmrmdir
# rmdir 仅用于删除空目录,如果要删除非空目录,需要使用 rm 命令

# rm -rf会递归地删除目录及其所有子目录和文件。选项 -r 表示递归删除,选项 -f 表示强制删除,即不提示确认。
$ rm -rf directory/
4. &&、||
# shell脚本也可以执行逻辑指令
# &&前面为真,故会正常echo
$ true && echo "hello peter parker"

# &&前面为假,故后面的echo不会执行
$ false && echo "hello peter parker"

# 逻辑或同理
5. ""''
# 单引号和双引号的区别 
# 双引号时输出:hello, I am in /home/xuyang
$ echo "hello, I am in $(pwd)"

# 双引号时输出:hello, I am in $(pwd)
$ echo 'hello, I am in $(pwd)'

# 拓展:$()是一种命令替换(command substitution)语法,用于将命令的输出结果作为变量的值进行引用。在$()中引用的变量可以是任何在命令中使用的变量或者环境变量。
6. |、||
# | 和 || 是两个不同的操作符,分别表示管道和逻辑或。
# | 用于将多个命令的输出连接起来进行数据流处理,而 || 用于在条件语句中指定多个条件中的任意一个满足即可执行相应的操作。
7. $0、$1、$2、$#、$$、$@、$?
# 在 Linux 系统中,$0 是一个特殊的变量,用于表示当前执行的脚本或命令的名称。
# 例如,在一个名为myscript.sh的bash脚本:
[
#!/bin/bash

echo "当前脚本的名称及路径为:$0"
]

# 当使用 ./myscript.sh 命令执行这个脚本时,
$ ./myscript.sh
# 输出的结果为:当前脚本的名称及路径为:./myscript.sh

# 此外,如果需要获取脚本或命令的参数或选项,可以使用 $1、$2、$3 等等来表示对应的参数或选项,例如:
# 例如,在一个名为myscript.sh的bash脚本:
[
#!/bin/bash

echo "当前脚本的第一个参数为:$1"
]

# 当使用 ./myscript.sh hello 命令执行这个脚本时,
$ ./myscript.sh hello 
# 输出的结果为:当前脚本的第一个参数为:hello
# $# 是一个特殊的变量,用于表示传递给脚本或函数的参数个数。具体来说,$# 表示命令行上给出的参数个数,但不包括命令本身。

# $@ 是一个特殊的变量,用于表示传递给脚本或函数的所有参数列表,每个参数都是一个独立的字符串。具体来说,$@ 表示所有参数列表,但不包括命令本身。

# $$ 是一个特殊的变量,用于表示当前进程的进程ID号(PID),即 Shell 或脚本本身的进程 ID。具体来说,$$ 表示当前进程的ID,是一个整数值。

# 在Ubuntu中,echo $?是一个命令,用于显示上一个命令的退出状态码(Exit status code)。每个命令在执行完成后都会返回一个退出状态码,来表示命令执行的结果。0表示成功,非0值表示失败或错误。
$ echo $?
8. grep
# grep 命令用于在文本文件中查找匹配的字符串:grep [options] pattern [file ...]
# 其中,options为可选参数,pattern为要查找的字符串或正则表达式,file为要查找的文件名。如果省略 file 参数,则默认从标准输入中读取数据进行匹配。

# 下面是 grep 命令的一些常见选项:
  # -i:忽略大小写进行匹配。
  # -v:反向匹配,输出不匹配的行。
  # -w:匹配整个单词,而不是匹配字符串的一部分。
  # -r:递归查找指定目录下的所有文件。
  # -n:输出匹配行的行号。
  # -c:仅输出匹配行的数量,而不是具体的匹配内容。
  
# 在文件file.txt中查找包含字符串 "hello" 的行
grep "hello" file.txt

# 在多个文件中查找包含字符串 "hello" 的行
grep "hello" file1.txt file2.txt file3.txt

# 在文件 `file.txt` 中查找包含字符串 "hello" 的行,忽略大小写
grep -i "hello" file.txt

# 在文件 `file.txt` 中查找不包含字符串 "hello" 的行
grep -v "hello" file.txt

# 在文件 `file.txt` 中查找包含整个单词 "hello" 的行
grep -w "hello" file.txt

# 在目录 `/path/to/directory` 及其子目录中递归查找包含字符串 "hello" 的行
grep -r "hello" /path/to/directory

# 在文件 `file.txt` 中查找包含字符串 "hello" 的行,并输出行号
grep -n "hello" file.txt

# 在文件 `file.txt` 中查找包含字符串 "hello" 的行,并输出匹配行的数量
grep -c "hello" file.txt
9. find
# 在某一目录下查找tools.txt文件
find /home/user/dir -name "tools.txt"
# 在某一目录下查找所有的.txt文件
find /home/user/dir -name "*.txt"

# 在某一目录下查找src文件夹(目录)
find /home/user/dir -name "src" -type d
10. locate
# 相比于find指令,locate的检索速度会快很多;默认在整个根目录(/)下进行搜索
# 在系统中查找是否存在某一文件夹或者文件,有的话会将绝对路径打印出来;如果没有输出任何信息,可以先updatedb一下
locate ros_ws

# 更新本地数据库后,可以再次查找
updatedb
11. shebang
# 在Linux系统中,shebang(也称为sha-bang或hashbang)是一种特殊的注释语法,用于指定脚本文件的解释器。shebang通常出现在脚本文件的第一行,其格式为:
#!interpreter [optional-arg] 
# 其中,interpreter是用于解释脚本文件的程序或脚本解释器的路径,而optional-arg则是可选的参数,用于指定解释器的选项或参数。
  • 例如,在一个Bash脚本中,可以使用以下shebang来指定Bash解释器:
# 这告诉系统在执行该脚本文件时,使用Bash解释器来解释该脚本文件。如果没有指定shebang,系统将默认使用/bin/sh作为解释器。
#!/bin/bash
12. convertffmpeg
# convert:处理图像
# ffmpeg:处理视频

# tldr类似于man,查看某一指令的使用手册,tldr同时会给出一些使用范例,非常清晰易用!但那是需要先安装tldr
$ tldr convert
$ tldr ffmpeg
13. nnn
# 非常好用的终端文件管理器,功能强大,几乎零配置,具有令人难以置信的性能,可能是您使用过得最快的!可以在 DE 和 GUI 实用程序无缝集成,具有独特的导航即可模式、自动选择、可分析磁盘使用情况,批量重命名,启动应用程序和选择文件。
sudo apt install nnn

# 快捷键大全:
# d:默认左侧不显示每个目录/文件对应的时间戳,快捷键d可以切换显示
# j:往下启动选中项
# k:往上移动
# l(L键):进入下一级文件夹
# h:切换到上一级文件夹
# G/g:G:直接跳到最下面;g:直接跳到最上面
# e:编辑文件
# /:搜索内容,先按一下/,再输入待搜索的字符
# .:显示隐藏文件,来回切换
# space:选中文件

# 移动/复制文件到某一目录:先按一下【space键】即可选中(可以依次选中多个文件);移动到指定目录后,按一下【v】,即可完成移动过程;如果按一下【p】,即可完成复制过程!
# 删除文件:选中文件后,按一下【x】,根据提示需要【y】进行确认。
# 文件重命名:同时按【ctr+R】,输入新名称,回车即可。

# 左上角的【1,2,3,4】是不同的工作区,相互隔离,互不影响
  • nnn管理器有很多独立的插件,比如图片/文本预览插件,可以到官方GitHub上下载安装,比较方便!
14. tar
  1. 压缩

    # 压缩包命名:archive.tar.gz
    tar -czvf archive.tar.gz ./
    
  2. 解压

    # 解压缩 .tar 文件
    tar -xvf file.tar
    
    # 解压缩 .tar.gz 或 .tgz 文件
    tar -xzvf file.tar.gz
    
    # 解压缩 .tar.bz2 文件
    tar -xjvf file.tar.bz2
    
15. 7z解压img
  1. 在Ubuntu下,可以使用p7zip-full软件包中的7z命令来解压img文件;

  2. 安装p7zip-full软件包:

    sudo apt-get update
    sudo apt-get install p7zip-full
    
  3. 解压

    7z x filename.img
    
    # 其中,`filename.img`是需要解压的img文件名。
    # 如果img文件是多个分卷文件,可以使用以下命令来解压:
    
    7z x filename.img.001
    # 其中,`filename.img.001`是分卷文件的名称,`.001`表示第一个分卷文件。
    
16. dmesg
  1. Linux dmesg(英文全称:display message)命令用于显示开机信息。kernel 会将开机信息存储在 ring buffer 中。您若是开机时来不及查看信息,可利用 dmesg 来查看。开机信息亦保存在 /var/log 目录中,名称为 dmesg 的文件里。

    dmesg [-cn][-s <缓冲区大小>]
    
    • -c  显示信息后,清除 ring buffer 中的内容。
    • -s <缓冲区大小>  预设置为 8196,刚好等于 ring buffer 的大小。
    • -n  设置记录信息的层级。
  2. 实例🌰:

    $ dmesg | less
    WARNING: terminal is not fully functional
    [  0.000000] Initializing cgroup subsys cpuset
    [  0.000000] Initializing cgroup subsys cpu
    [  0.000000] Linux version 2.6.32-21-generic (buildd@rothera) (gcc version 4.4.3 (Ub
    untu 4.4.3-4ubuntu5) ) #32-Ubuntu SMP Fri Apr 16 08:10:02 UTC 2010 (Ubuntu 2.6.32-21.3
    2-generic 2.6.32.11+drm33.2)
    [  0.000000] KERNEL supported cpus:
    [  0.000000]  Intel GenuineIntel
    [  0.000000]  AMD AuthenticAMD
    [  0.000000]  NSC Geode by NSC
    [  0.000000]  Cyrix CyrixInstead
    [  0.000000]  Centaur CentaurHauls
    [  0.000000]  Transmeta GenuineTMx86
    [  0.000000]  Transmeta TransmetaCPU
    [  0.000000]  UMC UMC UMC UMC
    [  0.000000] BIOS-provided physical RAM map:
    [  0.000000] BIOS-e820: 0000000000000000 - 000000000009f800 (usable)
    [  0.000000] BIOS-e820: 000000000009f800 - 00000000000a0000 (reserved)
    [  0.000000] BIOS-e820: 00000000000ca000 - 00000000000cc000 (reserved)
    [  0.000000] BIOS-e820: 00000000000dc000 - 00000000000e0000 (reserved)
    [  0.000000] BIOS-e820: 00000000000e4000 - 0000000000100000 (reserved)
    [  0.000000] BIOS-e820: 0000000000100000 - 000000003fef0000 (usable)
    [  0.000000] BIOS-e820: 000000003fef0000 - 000000003feff000 (ACPI data)
    [  0.000000] BIOS-e820: 000000003feff000 - 000000003ff00000 (ACPI NVS)
    
    ……省略部分内容
    
17. htopiotop
  • 通用监控工具 htop,是 top的改进版。htop 可以显示当前运行进程的多种统计信息;它有很多选项和快捷键,常见的有:<F6> 进程排序、 t 显示树状结构和 h 打开或折叠线程。

  • I/O 操作 - iotop 可以显示实时 I/O 占用信息而且可以非常方便地检查某个进程是否正在执行大量的磁盘读写操作;

    $ htop
    
    $ iotop
    
18. &>>&
  • &>的区别:

    • &:通常用于将一个命令放到后台运行,即在命令结尾处添加 & 符号;
    • >:重定向符,表示把前面输出的内容重定向到后面指定的位置
  • &>>&的区别:

    • &> :将命令的标准输出标准错误输出都重定向到指定的位置,即同时重定向标准输出和标准错误输出;
    • >& :将标准输出标准错误输出重定向到指定的位置。它的具体含义取决于它前面的数字是 1(标准输出)还是 2(标准错误输出);
  • 1>&21>2的区别:

    • 1>&2:1输出通道重定向到2输出通道,这里 &2 表示2输出通道;
    • 1>2
      • & 是一个描述符,如果1或2前不加&,只会被当成一个普通文件;
      • 1输出通道重定向到一个普通文件2中,注意这里没有&的加持,不能代表2输出通道。
  • shell中的文件描述符:这里的数字0/1/2是有特殊含义的!

    • 0 是一个文件描述符,表示标准输入STDIN
    • 1 是一个文件描述符,表示标准输出STDOUT
    • 2 是一个文件描述符,表示标准错误STDERR
  • 🌰举个栗子:

    • 当前目录只有一个文件a.txt
    $ ls 
    a.txt 
    
    $ ls a.txt b.txt 
    ls: b.txt: No such file or directory # 由于没有b.txt这个文件, 于是返回错误值, 这就是所谓的2输出 
    a.txt # 而这个就是所谓的1输出
    
    • 重定向:
    # 执行后没有任何返回值。原因是返回值都被重定向到相应的文件中了,想重定向谁,就写谁即可
    $ ls a.txt b.txt 1>file.out 2>file.err
    
    # 一般 `1>` 通常可以省略成 `>`,以下命令与上一命令等价
    $ ls a.txt b.txt >file.out 2>file.err
    
    $ cat file.out 
    a.txt 
    
    $ cat file.err 
    ls: b.txt: No such file or directory
    
    • 标准输出、标准错误输出均重定向到了file.out文件:
    # 以下两条等价
    $ ls a.txt b.txt 1>file.out 2>&1 
    $ ls a.txt b.txt &> file.out  # 简洁版
    
    $ cat file.out 
    ls: b.txt: No such file or directory 
    a.txt
    
19. ;、&&、&
  • 多条命令可以在终端中同一行使用;&&&隔开一起执行,但是作用有区别:
    • ;:有先后顺序,但是不管前面命令是否执行成功,后面的命令会紧接着执行;
    • &&:有先后顺序,并且要前面的命令执行成功后,才继续执行后面的命令;
    • &:所有命令同时执行,没有先后顺序。
20. df、du
  • 磁盘使用
    • df:显示每个分区的信息;
    • du:显示当前目录下每个文件的磁盘使用情况( disk usage)。-h 选项可以使命令以对人类(human)更加友好的格式显示数据;
    • ncdu是一个交互性更好的 du ,它可以让您在不同目录下导航、删除文件和文件夹;
21. 通配符
  • 注意:%并不是通配符;

    #  ? 任意单个字符
    #  * 任意0个或多个字符
    #  [ ] 匹配方括号中的任意一个字符,如[abc] 则匹配abc中的一个
    #  [ - ] "-"代表范围,例如:[a-z] 则匹配任意一个小写字母; [0-9] 则匹配任意一个0-9之间的数据,但是注意[0-10]不可以,不能超过9
    #  [^] 逻辑非,例如: [^0-9]匹配任意一个非数字字符
    
    # 创建20个文件
    for i in $(seq 1 1 20)
    do
        echo i > file${i}
    done
    
    # 删除file1 file2 ... file5
    rm file[1-5]
    
    touch a1 a2
    
    # 删除a开头的所有文件
    rm a*
    
    # 删除a2 b2 c2
    touch c1 c2
    rm [abc]2
    
22. xdg-open
  • 直接在命令行打开docpdfpng等文件,不用在文件管理器中一层层找;

    # 安装
    sudo apt-get update
    sudo apt-get install xdg-utils
    
    • 直接参数传入要打开的文件,等效于鼠标双击打开,系统会根据文件类型自动调用对应的程序:
    xdg-open  xxx.doc
    xdg-open  xxx.pdf
    xdg-open  xxx.png
    
    • 如果传入路径的话,则是使用默认的文件管理器打开界面:
    xdg-open  .
    xdg-open  ~/Downloads
    
    • 传入网址:
    xdg-open  www.google.com
    
23. xargs
  • 允许用户将标准输入的数据作为参数传递给其他命令,基本语法:

    command | xargs [options] [command]
    

    xargs 从标准输入读取数据,将其转换为命令行参数,并将其传递给 command 命令。

  • 示例🌰:

    # 将文件列表传递给 rm 命令,以删除这些文件
    find . -name "*.txt" | xargs rm
    
    # 将列表中的URL下载到当前目录,从urls.txt文件中读取URL并将其逐行传递给curl -O命令,其中-n 1指定每次只传递一个参数给curl
    cat urls.txt | xargs -n 1 curl -O
    
    # 将多个文件合并成一个文件
    find . -name "*.log" | xargs cat > all_logs.txt
    

2. 何为regular file

  • 如何理解Linux系统下的regular file?

    • 在Linux系统中,regular file 是一种常见的文件类型,通常指的是普通的文本文件或二进制文件,其中包含了用户创建或下载的数据和程序代码等信息。

    • 与之相对的是特殊文件(special file),包括目录文件、设备文件、命名管道、符号链接等。

    • regular file 文件类型通常与其他文件类型进行区分,例如目录文件(directory)用于存储其他文件和目录的信息,设备文件(device file)用于与硬件设备进行交互,命名管道(named pipe)用于进程间通信等。与之相比,regular file 文件类型的特点是具有一定的结构和格式,数据存储在文件中,并且可以被直接读取和编辑。

    • 在Linux系统中,使用 ls -l 命令可以查看文件的详细信息,其中第一个字符表示文件类型,- 表示 regular file 文件类型。例如:-rw-r--r-- 1 user user 0 Jun 28 15:00 file.txt

    • 在Linux系统中,file 命令可以用于识别文件类型,例如:file /bin/bash

      • 该命令可以识别 /bin/bash 文件为ELF 64-bit LSB可执行文件。

3. 脚本文件的执行方法

  • 在Linux系统中,source命令和./命令都可以用来执行脚本文件,但它们的执行方式和作用有所不同。

    1. source命令

      • source命令用于在当前shell环境下执行指定的脚本文件,并将其内容作为当前shell环境的一部分来处理。这意味着,脚本文件中定义的变量、函数和别名等将会在当前shell环境中生效,可以在当前shell环境中直接使用。使用source命令执行脚本文件的语法如下:

        source filename
        # or
        . filename
        
  1. ./命令

    • ./命令用于在新的子shell环境下执行指定的脚本文件。这意味着,脚本文件中定义的变量、函数和别名等只会在子shell环境中生效,不会对当前shell环境产生影响。使用./命令执行脚本文件的语法如下:

          ./filename
      
  • 因此,使用source命令可以将脚本文件的内容直接导入到当前shell环境中,方便在当前shell环境中直接使用脚本中定义的变量和函数等;而使用./命令则会在一个新的子shell环境中执行脚本文件,适用于需要在独立的环境中执行脚本文件的情况。

二、Tmux🍀

在这里插入图片描述

0. 参考链接

1. Tmux是啥?

  • Tmux 是一个终端复用器(terminal multiplexer),非常有用,属于常用的开发工具。类似的终端复用器还有 GNU Screen,Tmux 与它功能相似,但是更易用,也更强大。
  • Tmux 有多强:
    • 丝滑分屏(split),虽然 iTem2 也提供了横向和竖向分屏功能,但这种分屏功能非常拙劣,完全等同于屏幕新开一个窗口,新开的窗格(pane)不会自动进入到当前目录,也没有记住当前登录状态。这意味着如果 SSH 进入到远程服务器时,iTem2 新开的窗格(pane)中,依然要重新走一遍 SSH 登录的老路😢。Tmux 就不会这样,Tmux 窗口中,新开的窗格(pane),默认进入到之前的路径,如果是 SSH 连接,登录状态也依旧保持着😄,如此一来,我就可以随意的增删 pane,这种灵活性,好处不言而喻。
    • 保护现场(attach),即使命令行的工作只进行到一半,关闭终端后还可以重新进入到操作现场,继续工作。对于 SSH 远程连接而言,即使网络不稳定也没有关系,掉线后重新连接,可以直奔现场,之前运行中的任务,依旧在跑,就好像从来没有离开过一样;特别是在远程服务器上运行耗时的任务,Tmux 可以帮你一直保持住会话。如此一来,你就可以随时随地放心地进行移动办公,只要你附近的计算机装有 Tmux(没有你也可以花几分钟装一个),你就能继续刚才的工作。
    • 会话共享(适用于结对编程或远程教学),将 Tmux 会话的地址分享给他人,这样他们就可以通过 SSH 接入该会话。如果你要给同事演示远程服务器的操作,他不必直勾勾地盯着你的屏幕,借助 Tmux,他完全可以进入到你的会话,然后静静地看着他桌面上你风骚的键盘走位,只要他愿意,甚至还可以录个屏。
1.1 会话与进程
  • 命令行的典型使用方式:打开一个终端窗口(terminal window,以下简称“窗口”),在里面输入命令。用户与计算机的这种临时的交互,称为一次“会话”(session)
  • 会话的一个重要特点是,窗口与其中启动的进程是绑定的:打开窗口,会话开始;关闭窗口,会话结束,会话内部的进程也会随之终止,不管有没有运行完。
  • 一个典型的例子🌰就是,SSH登录远程计算机,打开一个远程窗口执行命令。这时,网络突然断线,再次登录的时候,是找不回上一次执行的命令的。因为上一次 SSH 会话已经终止了,里面的进程也随之消失了。
  • 为了解决这个问题,会话与窗口可以“解绑”:窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候,再让会话“绑定”其他窗口。
1.2 Tmux的作用
  • Tmux 就是会话与窗口的“解绑”工具,将它们彻底分离:

    • 它允许在单个窗口中,同时访问多个会话,这对于同时运行多个命令行程序很有用。
    • 它可以让新窗口“接入”已经存在的会话。
    • 它允许每个会话有多个连接窗口,因此可以多人实时共享会话。
    • 它还支持窗口任意的垂直和水平拆分。
  • 一定要搞清楚窗口、窗格、会话的关系:
    在这里插入图片描述

    如上图所示,Tmux 采用 C/S 模型构建,输入 tmux 命令就相当于开启了一个服务器,此时默认将新建一个会话,然后会话中默认新建一个窗口,窗口中默认新建一个窗格(pane,面板)。会话、窗口、面板之间的联系如下:

    • 一个Tmux session(会话)可以包含多个window(窗口),窗口默认充满会话界面,因此这些窗口中可以运行相关性不大的任务。
    • 一个window又可以包含多个pane(面板),窗口下的面板,都处于同一界面下,这些面板适合运行相关性高的任务,以便同时观察到它们的运行情况。

2. 基本用法

2.1 安装
  • 二进制安装:

    # Ubuntu 或 Debian
    $ sudo apt-get install tmux
    
    # CentOS 或 Fedora
    $ sudo yum install tmux
    
    # Mac
    $ brew install tmux
    
  • 源码安装:

    git clone https://github.com/tmux/tmux.git
    cd tmux
    sh autogen.sh
    ./configure && make
    
2.2 启动与退出
  • 直接在终端输入tmux命令,即可直接进入 Tmux 窗口;

  • 按下Ctrl+d或者显式输入exit命令,就可以退出 Tmux 窗口。

2.3 前缀键
  • Tmux 窗口有大量的快捷键。所有快捷键都要通过前缀键唤起
  • 默认的前缀键是Ctrl+b,即先按下Ctrl+b,快捷键才会生效。
  • 举个栗子🌰:
    • 帮助命令的快捷键是Ctrl+b ?:在 Tmux 窗口中,先按下Ctrl+b,再按下?,就会显示帮助信息。
    • 按下 ESC键或q键,就可以退出帮助。

3. 会话管理

3.1 新建会话
  • 第一个启动的 Tmux 窗口,编号是0,第二个窗口的编号是1,以此类推。这些窗口对应的会话,就是 0 号会话、1 号会话。⚠️会话和窗口是不同的概念!​

  • 启动 Tmux 后,底部 [0] 表示第 0 个 Tmux 伪窗口,如果再启动一个 Tmux 伪窗口时则为 [1],依次递增。

  • 但使用编号来区分会话,不太直观,更好的方法是为会话起名。

    # 新建一个无名称的会话
    $ tmux 
    
    # 新建一个指定名称的会话
    $ tmux new -s <session-name>
    

    底部不再是数字,而是命名的名字,如下图:

    在这里插入图片描述

3.2 查看会话
  • tmux ls命令可以查看当前所有的 Tmux 会话:

    $ tmux ls
    # or
    $ tmux list-session
    

    在这里插入图片描述

  • 如果刚好处于会话中,怎么查看所有会话?别担心,可以使用对应的 tmux 快捷键Ctrl+b + s,此时 tmux 将打开一个会话列表,按上下键(⬆︎⬇︎)或者鼠标滚轮,可选中目标会话,按左右键(⬅︎➜)可收起或展开会话的窗口,选中目标会话或窗口后,按回车键即可完成切换:

    在这里插入图片描述

3.3 分离会话
  • 在 Tmux 窗口中,按下Ctrl+b d或者输入tmux detach命令,就会将当前会话与当前窗口分离

    # 在 tmux 的任何一个窗格中输入如下命令
    $ tmux detach
    
  • 上面命令执行后,就会退出当前 Tmux 窗口,但是会话和里面的进程仍然在后台运行

3.4 接入会话
  • tmux attach命令用于重新接入某个已存在的 Tmux 会话:

    # 使用会话编号重新接入
    $ tmux attach -t 0
    
    # 使用会话名称重新接入
    $ tmux attach -t <session-name>
    
3.5 杀掉会话
  • tmux kill-session命令用于杀死某个会话:

    # 使用会话编号
    $ tmux kill-session -t 0
    
    # 使用会话名称
    $ tmux kill-session -t <session-name>
    
    # 关闭服务器,所有的会话都将关闭
    $ tmux kill-server 
    
3.6 切换会话
  • tmux switch命令用于切换会话:

    # 使用会话编号
    $ tmux switch -t 0
    
    # 使用会话名称
    $ tmux switch -t <session-name>
    
3.7 重命名会话
  • tmux rename-session命令用于重命名会话:

    # 将0号会话进行重命名
    $ tmux rename-session -t 0 <new-name>
    
    $ tmux rename-session -t old-session new-session
    
3.8 会话(系统)快捷键
前缀指令描述
Ctrl+b?显示快捷键的帮助文档
Ctrl+bd分离(断开)当前会话
Ctrl+bD选择要分离(断开)的会话
Ctrl+bCtrl+z挂起当前会话
Ctrl+br强制重载当前会话
Ctrl+bs显示会话列表用于选择并切换
Ctrl+b:进入命令行模式,此时可直接输入ls等命令
Ctrl+b[进入复制模式,按q退出
Ctrl+b]粘贴复制模式中复制的文本
Ctrl+b~列出提示信息缓存

4. Tmux简易操作流程

  1. 新建会话tmux new -s my_session
  2. 在 Tmux 窗口运行所需的程序。
  3. 按下快捷键Ctrl+b d将当前会话与窗口分离。
  4. 下次使用时,重新连接到会话tmux attach-session -t my_session

5. 窗口管理

  • 除了将一个窗口划分成多个窗格,Tmux 也允许新建多个窗口。
5.1 新建窗口
  • tmux new-window命令用来创建新窗口:

    $ tmux new-window
    
    # 新建一个指定名称的窗口
    $ tmux new-window -n <window-name>
    
5.2 切换窗口
  • tmux select-window命令用来切换窗口:

    # 切换到指定编号的窗口
    $ tmux select-window -t <window-number>
    
    # 切换到指定名称的窗口
    $ tmux select-window -t <window-name>
    
5.3 重命名窗口
  • tmux rename-window命令用于为当前窗口起名(或重命名):

    $ tmux rename-window <new-name>
    
5.4 关闭窗口
  • tmux kill-window命令用于关闭当前窗口:

    $ tmux kill-window -t <window-name>
    
5.5 窗口快捷键
  • 窗口操作快捷键:

    前缀指令描述
    Ctrl+bc新建窗口,状态栏会显示多个窗口的信息
    Ctrl+b&关闭当前窗口(关闭前需输入y or n确认);使用关闭窗格的命令亦可!
    Ctrl+b0~9切换到指定编号的窗口
    Ctrl+bp切换到上一窗口(按照状态栏上的顺序)
    Ctrl+bn切换到下一窗口
    Ctrl+bw打开窗口列表,且用于切换窗口
    Ctrl+b,重命名当前窗口
    Ctrl+b.修改当前窗口编号(适用于窗口重新排序)
    Ctrl+bf快速定位到窗口(输入关键字匹配窗口名称)

6. 窗格操作

  • Tmux 可以将窗口分成多个窗格(pane),每个窗格可以运行不同的命令。以下命令都是在 Tmux 窗口中执行。
6.1 划分窗格
  • tmux split-window命令用来划分窗格:

    # 划分上下两个窗格
    $ tmux split-window
    
    # 划分左右两个窗格
    $ tmux split-window -h
    

    在这里插入图片描述

6.2 选中窗格
  • tmux select-pane命令用来在不同窗格间进行选中切换:

    # 光标切换到上方窗格
    $ tmux select-pane -U
    
    # 光标切换到下方窗格
    $ tmux select-pane -D
    
    # 光标切换到左边窗格
    $ tmux select-pane -L
    
    # 光标切换到右边窗格
    $ tmux select-pane -R
    
6.3 交换窗格位置
  • tmux swap-pane命令用来交换窗格位置:

    # 当前窗格上移
    $ tmux swap-pane -U
    
    # 当前窗格下移
    $ tmux swap-pane -D
    
    # 左移、右移同理
    
6.4 关闭窗格
`Ctrl+b x`:关闭当前窗格。
# or
`ctrl+d`,记住如果只有一个窗格就是关闭整个窗口了!
6.5 Tmux上下翻屏
  • 先使用快捷键ctrl+b [ ,再可以通过方向键上下滚动即可,或者使用PageUpPageDown可以实现上下翻页。
6.6 窗格快捷键
  • 窗格操作快捷键:
    • Ctrl+b %:划分左右两个窗格,右侧新建面板。
    • Ctrl+b ":划分上下两个窗格,下侧新建面板。
    • Ctrl+b <arrow key>:光标切换到其他窗格。<arrow key>是指向要切换到的窗格的方向键,比如切换到下方窗格,就按方向键
    • Ctrl+b Space:在自带的窗格布局中循环切换。
    • Ctrl+b ;:光标切换到上一个窗格。
    • Ctrl+b o:光标切换到下一个窗格。
    • Ctrl+b {:当前窗格与上一个窗格交换位置。
    • Ctrl+b }:当前窗格与下一个窗格交换位置。
    • Ctrl+b Ctrl+o:所有窗格向前移动一个位置,第一个窗格变成最后一个窗格。
    • Ctrl+b Alt+o:所有窗格向后移动一个位置,最后一个窗格变成第一个窗格。
    • Ctrl+b x:关闭当前窗格。
    • Ctrl+b !:将当前窗格拆分为一个独立窗口。
    • Ctrl+b z:当前窗格全屏显示,再使用一次会变回原来大小。
    • Ctrl+b Ctrl+<arrow key>:按箭头方向调整窗格大小。
    • Ctrl+b q:显示当前窗口下所有窗格的编号。PS:看到屏幕上会在每个窗格上显示出各自编号,此时迅速点击对应的编号,即可跳转到对应的窗格。
    • Ctrl+b t:显示时钟。

7. 其他Tmux命令

# 列出所有快捷键,及其对应的 Tmux 命令
$ tmux list-keys

# 列出所有 Tmux 命令及其参数
$ tmux list-commands

# 列出当前所有 Tmux 会话的信息
$ tmux info

# 重新加载当前的 Tmux 配置
$ tmux source-file ~/.tmux.conf

8. 灵活配置Tmux

  • Tmux 的丝滑分屏功能正是得益于以上系统、窗口、面板的快捷指令,只要你愿意,你就可以解除任意的快捷指令,然后绑上你喜欢的指令,当然这就涉及到它的可配置性了,请继续往下读。
  • 除了快捷指令外,tmux 还提供了类似 vim 的配置性功能。可配置性是软件的一项进阶级功能,只有具备了可配置性,软件才有了鲜活的个性,用户才能体会到操作的快感。
8.0 完整配置文件
  • 详情请参考:

    Github Repo - Useful_tools - 自定义软件配置 - Linux - home - xuyang - .tmux.conf & .config/tmux

    • 其中涉及到powerline等插件,具体安装过程可参考官方文档(对应的bilibili视频教学)。
    • 一定要结合 ChatGPT 弄懂各项配置的含义,坚决杜绝为了配置而配置!
8.1 修改指令前缀
  • 相信只要你用过几次 tmux,就会发现Ctrl+b指令前缀,着实不太方便。这两个键相距太远,按键成本太高了。因此我们首先需要将它更换为距离更近的Ctrl+a组合键,或者其他任意你喜欢的组合键。

  • Tmux 的用户级配置文件为~/.tmux.conf(没有的话就创建一个),修改快捷指令,只需要增加如下三行即可:

    set -g prefix C-a #
    unbind C-b # C-b即Ctrl+b键,unbind意味着解除绑定
    bind C-a send-prefix # 绑定Ctrl+a为新的指令前缀
    
    # 从tmux v1.6版起,支持设置第二个指令前缀
    set-option -g prefix2 ` # 设置一个不常用的`键作为指令前缀,按键更快些
    

    修改的~/.tmux.conf配置文件有如下两种方式可以令其生效:

    • 重启 tmux。
    • 在 tmux 窗口中,先按下Ctrl+b指令前缀,然后按下系统指令:,进入到命令模式后输入source-file ~/.tmux.conf,回车后生效。
  • 既然快捷指令如此方便,更为优雅的做法是新增一个加载配置文件的快捷指令,这样就可以随时随地 load 新的配置了,如下所示:

# 绑定快捷键为r
bind r source-file ~/.tmux.conf \; display-message "Config reloaded.."
  • 请特别注意⚠️,在已经创建的窗口中,即使加载了新的配置,旧的配置依然有效(只要你新加的功能没有覆盖旧的配置,因此如果你第一次绑定快捷指令为x键,然后又改为绑定y键,那么xy都将有效),新建会话不受此影响,将直接采用新的配置。

  • 既然我们已经迈出配置化的第一步,那么接下来我们可以做得更多。

8.2 新增窗格(面板)
  • tmux 中,使用最多的功能之一就是新增一个面板。水平方向新增面板的指令是 prefix + " ,垂直方向是 prefix + %"%需要两个键同时按下才能完成,加上指令前缀至少需要 3-4 次按键才能组成一个完整的指令,同时这个两个键也不够醒目和方便,因此我们可以绑定两个更常用的指令-|,如下所示:

    unbind '"'
    bind - splitw -v -c '#{pane_current_path}' # 垂直方向新增面板,默认进入当前目录
    unbind %
    bind | splitw -h -c '#{pane_current_path}' # 水平方向新增面板,默认进入当前目录
    
8.3 开启鼠标支持
  • 默认情况下,tmux 的多窗口之间的切换以及面板大小调整,需要输入指令才能完成,这一过程,涉及到的指令较多,而且操作麻烦,特别是面板大小调整,指令难以一步到位,这个时候开启鼠标支持就完美了。

  • 对于 tmux v2.1 (2015.10.28) 之前的版本,需加入如下配置:

    setw -g mode-mouse on # 支持鼠标选取文本等
    setw -g mouse-resize-pane on # 支持鼠标拖动调整面板的大小(通过拖动面板间的分割线)
    setw -g mouse-select-pane on # 支持鼠标选中并切换面板
    setw -g mouse-select-window on # 支持鼠标选中并切换窗口(通过点击状态栏窗口名称)
    

    有的地方可能会出现set-window-option的写法,setw就是它的别名。

  • 对于 tmux v2.1 及以上的版本,仅需加入如下配置:

    set-option -g mouse on # 等同于以上4个指令的效果
    
  • 需要注意的是,开启鼠标支持后,iTem2 默认的鼠标选中即复制功能需要同时按下 Alt 键,才会生效。

8.4 快速窗格(面板)切换
  • 鼠标支持确实能带来很大的便捷性,特别是对于习惯了鼠标操作的 tmux 新手,但对于键盘爱好者而言,这不是什么好消息,对他们而言,双手不离键盘是基本素质。

  • 虽然指令前缀加方向键可以切换面板,但方向键太远,不够快,不够 Geek。没关系,我们可以将面板切换升级为熟悉的hjkl键位。

    # 绑定 h、j、k、l 键为面板切换的上、下、左、右键
    bind -r k select-pane -U   # 绑定k为↑
    bind -r j select-pane -D   # 绑定j为↓
    bind -r h select-pane -L   # 绑定h为←
    bind -r l select-pane -R   # 绑定l为→
    
  • -r表示可重复按键,大概 500ms 之内,重复的hjkl按键都将有效,完美支持了快速切换的 Geek 需求。

  • 除了上下左右外, 还有几个快捷指令可以设置:

    bind -r e lastp     # 选择最后一个窗格(面板)
    bind -r ^e last     # 选择最后一个窗口,^e表示Ctrl+e
    
    bind -r ^u swapp -U # 与前一个面板交换位置
    bind -r ^d swapp -D # 与后一个面板交换位置
    
8.5 窗格(面板)大小调整
  • 习惯了全键盘操作后,命令的便捷性不言而喻。既然面板切换的指令都可以升级,面板大小调整的指令自然也不能落后。如下配置就可以升级你的操作:

    # 绑定Ctrl+h、j、k、l键为窗格上下左右调整边缘的快捷指令
    bind -r ^k resizep -U 10 # 绑定Ctrl+k为往↑调整面板边缘10个单元格
    bind -r ^j resizep -D 10 # 绑定Ctrl+j为往↓调整面板边缘10个单元格
    bind -r ^h resizep -L 10 # 绑定Ctrl+h为往←调整面板边缘10个单元格
    bind -r ^l resizep -R 10 # 绑定Ctrl+l为往→调整面板边缘10个单元格
    

    以上,resizepresize-pane的别名。

8.6 窗格(面板)最大化
  • 当窗口中面板的数量逐渐增多时,每个面板的空间就会逐渐减少。为了保证有足够的空间显示内容,tmux 从 v1.8 版本起,提供了面板的最大化功能,输入tmux-prefix + z,就可以最大化当前面板至窗口大小,只要再重复输入一次,便恢复正常。那么 tmux v1.8 以下的版本,怎么办呢?别急,有大神提供了如下的解决方案。

  • 首先编写一个 zoom 脚本,该脚本通过新建一个窗口,交换当前面板与新的窗口默认面板位置,来模拟最大的功能;通过重复一次按键,还原面板位置,并关闭新建的窗口,来模拟还原功能,如下所示:

    #!/bin/bash -f
    currentwindow=`tmux list-window | tr '\t' ' ' | sed -n -e '/(active)/s/^[^:]*: *\([^ ]*\) .*/\1/gp'`;
    currentpane=`tmux list-panes | sed -n -e '/(active)/s/^\([^:]*\):.*/\1/gp'`;
    panecount=`tmux list-panes | wc | sed -e 's/^ *//g' -e 's/ .*$//g'`;
    inzoom=`echo $currentwindow | sed -n -e '/^zoom/p'`;
    if [ $panecount -ne 1 ]; then
        inzoom="";
    fi
    if [ $inzoom ]; then
        lastpane=`echo $currentwindow | rev | cut -f 1 -d '@' | rev`;
        lastwindow=`echo $currentwindow | cut -f 2- -d '@' | rev | cut -f 2- -d '@' | rev`;
        tmux select-window -t $lastwindow;
        tmux select-pane -t $lastpane;
        tmux swap-pane -s $currentwindow;
        tmux kill-window -t $currentwindow;
    else
        newwindowname=zoom@$currentwindow@$currentpane;
        tmux new-window -d -n $newwindowname;
        tmux swap-pane -s $newwindowname;
        tmux select-window -t $newwindowname;
    fi
    
  • 不妨将该脚本存放在~/.tmux目录中(没有则新建目录),接下来只需要绑定一个快捷指令就行:

    unbind z
    bind z run ". ~/.tmux/zoom"
    
8.7 窗口变为窗格(面板)

试想这样一个场景:当你打开多个窗口后,然后想将其中几个窗口合并到当前窗口中,以便对比观察输出。

  • 通过上面的 zoom 脚本,面板可以轻松地最大化为一个新的窗口。那么反过来,窗口是不是可以最小化为一个面板呢?

  • 实际上,你的要求就是将其它窗口变成面板,然后合并到当前窗口中。对于这种操作,我们可以在当前窗口,按下tmux-prefix + :,打开命令行,然后输入如下命令:

    join-pane -s window01    # 合并名称为window01的窗口的默认(第一个)面板到当前窗口中
    join-pane -s window01.1  # .1显式指定了第一个面板,.2就是第二个面板(我本地将面板编号起始值设置为1,如果你没有改的话,这里默认应该是0)
    
  • 每次执行join-pane命令都会合并一个面板,并且指定的窗口会减少一个面板,直到面板数量为0,窗口关闭。

  • 除了在当前会话中操作外,join-pane命令甚至可以从其它指定会话中合并面板,格式为join-pane -s [session_name]:[window].[pane],如join-pane -s 2:1.1 即合并第二个会话的第一个窗口的第一个面板到当前窗口,当目标会话的窗口和面板数量为0时,会话便会关闭。

  • 注⚠️:上一节中的swap-pane命令与join-pane语法基本一致。