初衷只是为了记述一下在 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 toemacs'
emacs'
keymap is set to
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 键绑定呢?或者说如何在两者之间切换,命令分别是
set -o vi
切换到 Vi 键绑定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 tovi'
vi-insert'
keymap is set to
现在命令行的输入操控方式来到了 Vi 模式了,Esc
在 Vi 的正常模式与输入模式之间切换,v
键不再是可视模式,而是直接打开 $EDITOR
指示的编辑器(默认为 vi), 载入当前命令进行编辑,退出后立即执行。
Vi 键绑定下可以尝试大多数 Vi 的操作,例如
- h, j, k, l 前下上右单字符的移动光标
- w, e, b 在单词间的移动
- 0, ^, $ 跳到行首, 或行尾
- x 删除当前字符,dd 删除当前行,S 删除当前行并切到输入模式
- A, I 分别把光标移到行尾,行首并切换到输入模式。因为命令行是单行,所以 o, O 不起作用了
- 搭配数字或 Motion 操作,如 dw 删除当前字符到当前词尾(带空白),d2w 删除当前字符到下两个词尾(带空白)。d$ 删除到行尾
- / 搜索历史命令也能用,不过还是推荐用
ctrl + r
的reverse-search-history
更多的类似 Vi 的操作请参看 Vi 操作指南。 在 Vi 键绑定时有些 Emacs 键绑定的快捷操作也还能用,多试一试不会怀孕的。
参考:
- Bash Keyboard Shortcuts
- Bash bind 命令的用法
- GNU Readline
- Bindable Readline Commands
- Bash Reference Manual
本文链接 https://yanbin.blog/bash-emacs-vi-key-bindings/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。