Bash 下的 emacs 和 vi 键绑定

初衷只是为了记述一下在 Bash/Zsh 中怎么调用 Vi 编辑当前的命令,但一发挥便涉及到了 Bash/Zsh 的键绑定的话题,无法打住,只得另立新篇。这里也只说 Bash 的键绑定,不会有 Zsh 键绑定的内容。

什么是 Bash 的键绑定(keybing) 呢? 就是在 Bash 中的快捷键方案,即相当于某个 IDE 的快捷键配置,或者叫 Keymap。比如说 IntelliJ IDEA 中可选择的 Keymap 有 Eclipse, Emacs, JBuilder, Mac OS X, Mac OS X 10.5+, NetBean, Visual Studio, 以满足不同使用者的习惯。

相应的 Bash 也为我们提供了两种键绑定的方案,即 emacs(默认) 和 vi 键绑定类型。

Emacs 键绑定

我们大多数天天在 Bash 下无意识中使用着 Emacs 键绑定类型,即使可能从未用过 Emacs 本身。比如我们在 Bash 下的按键组合

ctrl + a     跳到命令行的开始
ctrl + e     跳到命令行末尾
!!               重复最后一个命令
ctrl + l      清屏操作,类似于  clear 命令
ctrl + c      中断/杀掉当前运行的进程 (SIGINT)
ctrl + d     发送 EOF 标记,这会关掉当前的 shell (EXIT)
ctrl + z      发送 SIGTSTP 给当前任务,使其挂起送到后台。(所以如果 vi 未正常退出,而是按 ctrl + z 的话,vi 进程还呆在后台

它们都是来自于 Emacs 键绑定。是不是那么的熟悉啊?

当前的键绑定类型

我们说过,Bash 默认的键绑定是 Emacs,基本上在终端中按下 ctrl + l 看是否能成功清屏就知道是否是 Emacs 键绑定,当然 Vi 绑定也可以自定义 ctrl + l 来清屏。

更准确的办法是用 bind 命令,这是一个 Bash 内置的命令。bind -V 可以看到所有设置,bind -V | grep -e editing -e keymap 显示编辑模式与键映射

$ bind -V | grep -e editing -e keymap
editing-mode is set to emacs'
keymap is set to
emacs'

bind -v 能看到某个属性可以怎么用 set 命令去设置

显示当前的按键绑定

使用命令 bind -p 几乎列出了所有的可绑定的按键操作,包括单个字母键标识为 self-insert,和组合键操作,共有大约 478 个键绑定。bind -p | grep -F "\C" 列出  ctrl 开始的键组合

$ bind -p | grep -F "\C"
"\C-g": abort
"\C-x\C-g": abort
......
"\C-x\C-e": edit-and-execute-command
......
"\C-p": previous-history
"\C-q": quoted-insert
"\C-v": quoted-insert
"\C-x\C-r": re-read-init-file
"\C-r": reverse-search-history
......

bind -P 列出当前 readline 函数名和键绑定

切换到 Vi 键绑定

既然说 Bash  有两种类型的键绑定,并且平时对 Vi 表现出更强烈的热爱,该如何切换成 Vi 键绑定呢?或者说如何在两者之间切换,命令分别是

  1. set -o vi 切换到  Vi 键绑定
  2. set -o emacs 切换到  Emacs 键绑定

一旦我们切换到了 Vi 键绑定,会发现有些键 ctrl + a, ctrl + l 不管用了,但 ctrl + c, ctrl + z 还是一样的。确认是否是 Vi 键绑定,可以执行 bind -V | grep -e editing -e keymap,

$ bind -V | grep -e editing -e keymap
editing-mode is set to vi'
keymap is set to
vi-insert'

现在命令行的输入操控方式来到了 Vi 模式了,Esc 在  Vi 的正常模式与输入模式之间切换,v 键不再是可视模式,而是直接打开 $EDITOR 指示的编辑器(默认为 vi), 载入当前命令进行编辑,退出后立即执行。

Vi 键绑定下可以尝试大多数 Vi 的操作,例如

  1. h, j, k, l 前下上右单字符的移动光标
  2. w, e, b 在单词间的移动
  3. 0, ^, $ 跳到行首, 或行尾
  4. x 删除当前字符,dd 删除当前行,S 删除当前行并切到输入模式
  5. A, I 分别把光标移到行尾,行首并切换到输入模式。因为命令行是单行,所以  o, O 不起作用了
  6. 搭配数字或 Motion 操作,如 dw 删除当前字符到当前词尾(带空白),d2w 删除当前字符到下两个词尾(带空白)。d$ 删除到行尾
  7. /  搜索历史命令也能用,不过还是推荐用 ctrl + r 的 reverse-search-history

更多的类似 Vi 的操作请参看 Vi 操作指南。 在 Vi 键绑定时有些 Emacs 键绑定的快捷操作也还能用,多试一试不会怀孕的。

参考:

  1. Bash Keyboard Shortcuts
  2. Bash bind 命令的用法
  3. GNU Readline
  4. Bindable Readline Commands
  5. Bash Reference Manual

本文链接 https://yanbin.blog/bash-emacs-vi-key-bindings/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments