Vim 使用技巧整理
Vim 是 VIMproved 的缩写,即 Vim 编辑器是 Vi 编辑器的改进版。Vim 采用模式编辑的理念,其提供多种操作模式,按键在不同的模式下作用不同。 如,普通模式用于浏览文件,插入模式用于插入文本,可视模式下可以选择行或文本块,命令模式可以执行命令等等。
和模式编辑紧密相连的概念是 操作符
和 动作
。操作符 指的是开始某个行为,如修改、删除或者选择文本;之后你要用一个 动作 来指定需要操作的文本区域。比如,要改变括号内的文本,需要执行 ci(
(读做 change inner parentheses);删除整个段落的内容,需要执行 dap
(读做:delete around paragraph)。
Vim 存在一个兼容模式,该模式让 Vim 兼容 Vi。在兼容模式下运行时,Vim 大部分增强及改善的功能将不可用。需注意的是,这种模式下,Vim 并不能简单等同 Vi - 此模式只是设定一些类似 Vi 编辑器工作方式的默认选项。
Vim 包含三种不同的操作模式,即 命令模式(或者叫 普通模式)、插入模式、底行命令模式。使用 ESC
,i
/o
/a
等,:
来切换不同模式。打开 Vim 时,默认停留在 命令模式,按 i 等键可以进入 插入模式 进行文本编辑,按 ESC 键可以退出编辑模式,然后输入 : 可进入底行命令模式。编辑模式和底行命令模式都只能从命令模式进入,ESC 键主要用于退出编辑模式和底行命令模式。另外,还有两种常用的工作模式,可视模式 (Visual-mode) 与 粘贴模式(Paste-mode)。
在以下的描述中,所有以 :
开头的命令都表示在底行命令模式下的命令,所有不以 : 开头的命令都表示在普通模式下的命令。
Vim 自带一个交互式的教程,包含一些基础的操作,可以通过终端运行以下命令打开教程来练习使用:
$ vimtutor
基础
打开文件
从命令行中打开:
打开文件
$ vim filename
当指定一个目录时会打开一个目录树
$ vim dirname
打开多个文件并横向分屏
$ vim -o file1 file2 file3
打开多个文件并纵向分屏
$ vim -o file1 file2 file3
打开文件并调到指定行
$ vim filename +num
在打开文件前,先执行指定的命令
vim -c cmd filename
恢复上次异常退出的文件
vim -r filename
以只读的方式打开文件,但可以强制保存
vim -R filename
只读的方式打开文件,不可以强制保存
vim -M filename
打开文件,并将光标停留在第一个找到的 string 上
vim +/string filename
用已有的 vim 进程打开指定的文件
vim --remote filename
从 Vim 中打开文件:
打开文件
:e filename
打开目录树(默认打开当前目录)
:Ex dirname
打开一个文件并横向分屏
:sp filename
:split filename
打开一个文件并纵向分屏
:vsp filename
:vsplit filename
打开以光标所在字符串为文件名的文件
gf
保存与退出
:w -- 保存修改
:wa[ll] -- 保存所有修改过的窗口
:wq -- 保存并退出
:x -- 保存并退出
ZZ -- 保存并退出
:n1,n2w filename -- 选择性保存从某n1行到另n2行的内容
:saveas newfilename -- 另存为
:q[uit] -- 退出 vim
:q! -- 强制退出(放弃修改)
:qa[ll] -- 关闭所有窗口,退出vim
:close -- 关闭当前窗口
:only -- 只保留当前窗口,关闭其它窗口(CTRL-W o)
缓冲区
缓冲区是一个文件的内容占用的那部分 Vim 内存。每一份文件都是在他们自己独有的缓冲区打开的,每次文本都是作为缓冲区的一部分显示的。列出缓冲区可以用如下三个命令:
:buffers
:files
:ls
示例:
:ls
1 %a "test1" line 1
2 "test2" line 0
3 "test3" line 0
其中,第一列是文件编号,第二列是缓冲文件的状态,第三列是文件的名称,第四列是上一次编辑的位置。 缓冲文件的状态有如下几种(仅供参考):
-
非活动的缓冲区a
当前被激活缓冲区(光标所在的缓冲区)h
隐藏的缓冲区%
当前的缓冲区(指当前窗口可见的缓冲区,因为可以分割窗口,可能有多个)#
交换缓冲区=
只读缓冲区+
已经更改的缓冲区
切换工作区用 :buffer
/:b
命令,或者用 :sbuffer
/sb
:
:[s]b 编号
:[s]buffer 文件名
:[s]bn[ext]
:[s]bp[revious]
:[s]bl[ast]
:[s]bf[irst]
添加或删除缓冲区
添加一个文件到缓存区
:bad[d] 文件名
新建一个未命名的缓冲区
:enew
从缓冲区删除一个文件
:bdel[ete] 文件名/编号
参数列表
缓冲区列表是 Vim 的特性。在这之前的 vi 中,仅仅只有参数列表,参数列表在 Vim 中依旧可以使用。
每一个通过 shell 命令传递给 Vim 的文件名都被记录在一个参数列表中。可以有多个参数列表:默认情况下所有参数都被放在全局参数列表下,但是你可以使用 :arglocal
命令去创建一个新的本地窗口的参数列表。
使用 :args
命令可以列出当前参数。使用 :next
,:previous
,:first
,:last
命令可以切换在参数列表中的文件。通过使用 :argadd
,:argdelete
或者 :args
等命令改变参数列表。
参数列表在有些情况下是非常有用的,如使用 :argdo
做批处理,示例:
:args **/*.[ch]
:argdo %s/foo/bar/ge | update
以上命令将替换掉当前目录以及其子目录中所有的 C 源文件和头文件中的 “foo” 为 “bar”。:argdo
命令会对参数列表中的文件执行相同的动作。
更多关于参数列表的信息,可以通过查阅离线文档了解 :h argument-list
。
标签/窗口
窗口 是缓冲区更上一层的视窗。如果想同时查看几个文件或者查看同一文件的不同位置,则可以开启多个窗口。窗口可以水平或者竖直分割并且现有窗口的高度和宽度可以被调节。
打开多个窗口可以用以下命令:
# 横向打开一个新窗口
:sp[lit]
:sp[lit] filename
:new
:new filename
# 纵向打开一个新窗口
:vsp[lit]
:vsp[lit] filename
ctrl-w s 上下分割当前文件
ctrl-w v 左右分割当前文件
# 水平分割一个窗口,浏览文件系统
:Sex
# 垂直分割一个窗口,浏览文件系统
:Vex
窗口大小纵向调整:
:ctrl+w + 纵向扩大(行数增加)
:ctrl+w - 纵向缩小 (行数减少)
:res(ize) num 如 :res 5,显示行数调整为5行
:res(ize) +num 把当前窗口高度增加 num 行
:res(ize) -num 把当前窗口高度减少 num 行
窗口大小横向调整:
:vertical res(ize) num 指定当前窗口为num列
:vertical res(ize)+num 把当前窗口增加num列
:vertical res(ize)-num 把当前窗口减少num列
标签页 是可以容纳一系列 窗口 的容器。打开标签可以使用以下命令
:tabe[dit] [文件名]
:tabnew [文件名]
切换标签页:
# 下一个标签
gt
:tabn[ext]
# 上一个标签页
gT
:tabp[revious]
# 快速切换到第一个标签或最后一个标签
:tabfir[st] :tabr[ewind]
:tabl[ast]
使用 :e
或 ctrl+^
可以回到刚才编辑的文件,这已操作感觉很实用。
其他操作:
# 显示所有标签
:tabs
# 关闭标签
:tabc[lose]
# 关闭所有其他标签页,只保留当前活动标签页
:tabo[nly]
# 将当前标签页移到第 n 个标签页之后
:tabm[ove] N
# 同时在多个标签页中执行命令
:tabdo command
如 :tabdo %s/food/drink/g 可一次完成对所有文件的替换操作,而不用针对每个文件重复操作
随便说一下,缓冲区列表是全局可见的,可以在任何标签中访问任何一个缓冲区。
寄存器
寄存器是存储文本内容的空间。常用的「复制」操作就是把文本存储到寄存器,「粘贴」操作就是把文本从寄存器中读出来。例如常用的复制快捷键 y,粘贴快捷键 p,也都是对寄存器(匿名寄存器 Unnamed)的操作。
Vim 提供了大致 10 类共 48 个寄存器。寄存器以 "
开头进行标记,即 "{register}
。可以用 “{register}y 来拷贝到 {register} 中, 用 “{register}p 来粘贴 {register} 中的内容。如:”ayy 可以拷贝当前行到寄存器 a 中,而 “ap 则可以粘贴寄存器 a 中的内容。
寄存器大致分为以下几类:
- 匿名寄存器
""
- 编号寄存器
"0
到"9
- 小删除寄存器
"-
- 26 个命名寄存器
"a
到"z
- 3 个只读寄存器
":
,".
,"%
- Buffer 交替文件寄存器
"#
- 表达式寄存器
"=
- 选区和拖放寄存器
"*
,"+
,"~
- 黑洞寄存器
"_
- 搜索模式寄存器
"/
动作/操作符/文本对象
动作
值移动光标的操作,如熟悉 h、j、k 和 l,以及 w 和 b 等,/
, ?
也是一个动作。他们都可以搭配数字使用,比如 2?the
可以将光标移动到倒数第二个 “the” 出现的位置。可以通过 :h navigation
来查看支持的动作。
操作符
是对某个区域文本执行的操作。如,d、~、gU 和 > 都是操作符。这些操作符既可以在普通模式下使用,也可以在可视模式下使用。在普通模式中,顺序是先按操作符,再按动作指令,比如 >j。在可视模式中,选中区域后直接按操作符即可,比如 Vjd。操作符也可以搭配数字使用,比如 2gUw 可以将当前单词以及下一个单词转成大写。由于动作和操作符都可以搭配数字使用,因此 2gU2w 与执行两次 gU2w 效果是相同的。有关操作符的详细帮助,可以通过 :h operator
来查看。
文本对象
是双向选择的文本(动作是单向选择的)。文本对象操作可以选中符号(比如括号、中括号和大括号等)标记的范围内文本,也作用于整个单词、整个句子等其他情况。文本对象不能用于普通模式中移动光标的操作,因为光标还没有智能到可以向两个方向同时跳转。但这个功能可以在可视模式中实现,因为在对象的一端选中的情况下,光标只需要跳转到另一端就可以了。可以通过 :h text-objects
来详细了解关于文本对象的内容
文本对象操作一般用 i
或 a
加上对象标识符操作,其中 i
表示在对象内(英文 inner
)操作,a
表示对整个对象(英文 around
)操作,这时开头和结尾的空格都会被考虑进来。如,diw 可以删除当前单词,ca( 可以改变括号以及括号中的内容。
文本对象同样可以与数字搭配使用。比如,像 ((( ))) 这样的文本,假如光标位于最内层的括号上或最内层的括号内,那么 d2a( 将会删除从最内层开始的两对括号,以及他们之间的所有内容。其实,d2a( 这个操作等同于 2da(。需要注意的是,在 Vim 的命令中,如果有两处都可以接收数字作为参数,那么最终结果就等同于两个数字相乘。在这里,d 与 a( 都是可以接收参数的,一个参数是 1,另一个是 2,也可以把它们相乘然后放到最前面。
配置
Vim 是一个可高度定制的编辑器,对编辑器的定制通过添加配置项和插件来完成,其读取配置文件的顺序可以通过:
:version
来查看,如以下为 MacOSX 上的结果:
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
defaults file: "$VIMRUNTIME/defaults.vim"
fall-back for $VIM: "/usr/share/vim"
一些配置示例:https://github.com/kuanghy/vimconfig.
常用配置列举:
" 不要工作在 Vi 兼容的模式下
:set nocp
" 显示不可视字符
:set list
" 开启/取消粘贴模式
:set paste
:set nopaste
" 显示/隐藏行号
:set number
:set nu
:set nonumber
:set nonu
" 在搜索时忽略/不忽略大小写
:set ic
:set noic
:set fileencoding " 查看文件编码
:set fileencoding=utf-8 " 转换文件编码
:set fileformat? " 查看文件格式
:set fileformat=unix " 设置文件格式
:set bomb? " 查询 BOM
:set bomb " 添加 BOM
:set nobomb " 删除BOM
配置 Vim 支持系统剪切板,首先查看 Vim 本身是否支持:
vim --version | grep clipboard
输出的 clipboard 和 xterm_clipboard 前面为加号(+)表示支持,为减号(-)表示不支持。或者:
:echo has('clipboard')
输出 1 表示支持,输出 0 表示不支持。如果不支持可以尝试重新编译安装。支持系统剪切板后便可使用如下命令操作剪切板:
"+y 复制内容到系统剪切板
"+p 把系统剪切板里的内容粘贴到 vim
也可以配置 Vim 与系统剪切板共享复制粘贴(设置剪切板为匿名寄存器):
if has("clipboard")
set clipboard=unnamed " copy to the system clipboard
if has("unnamedplus") " X11 support
set clipboard+=unnamedplus
endif
endif
移动
单位级
h
向左一字符j
下一行k
上一行l
向右一字符
单词级
w
orW
向右移动到下一单词开头e
orE
向右移动到单词结尾b
orB
向左移动到单词开头
注:所有小写单词都是以分词符作为单词界限,大写字母以空格作为界限。
块级
(
移动到当前句子开头)
移动到下一句子开头{
移动到当前段落开头}
移动到下一段落开头+
移动到下一行开头-
移动到上一行开头gg
到文档第一行G
到文档最后一行0
,|
到行首(第 1 列)^
到第一个非空白字符$
到行尾0nl
,n|
到当前行的第n 列g_
到当前行的最后一个非空格字符处H
到屏幕的首行L
到屏幕尾行M
到屏幕中间%
到匹配的括号(包括小括号、中括号、大括号)zt
将当前行移到屏幕顶部zz
将当前行移到屏幕中部zb
将当前行移到屏幕底部Ctrl-d
向下移动半页Ctrl-u
向上移动半页Ctrl-f
向下移动一页Ctrl-b
向上移动一页:<N>
or<N>gg
跳转到第 N 行:+<N>
or<N>j
向下跳 N 行:-<N>
or<N>k
向上跳 N 行
注:| 表示 bar 的意思,是普通模式下用于跳转到当前行某一列的一个命令 (To screen column [count] in the current line),单个 |
表示当前行的第 0 列 (行首)。使用 0nl 跳转到指定列时,表示先用命令 0 将光标移动到行首,nl 表示执行 n 次向右移动光标操作;使用 n | 时,表示使用 | 命令跳转到当前行的第 n 列。 |
编辑
插入
执行插入操作需进入 插入模式,以下操作均可实现插入操作:
i 在当前光标位置插入字符
I 在当前行首位置插入字符
o 在当前行往下插入新的一空行
O 在当前行往上插入新的一空行
a 在当前光标后追加字符
A 在当前行尾追加字符
r 替换当前字符
R 替换当前光标的字符直到退出插入模式(按ESC)
c 删除选中文本并进入插入模式
C 删除至行尾并进入插入模式
s 删除当前字符并进入插入模式
S 删除当前行并进入插入模式
:r filename 把文件的内容插入当前行的下一行
:r! command 把命令返回的结果插入到当前行的下一行
复制与粘贴
y
(yanking)操作符用于复制文本,p
操作符用于粘贴文本,以下列举常用的复制操作:
yw 拷贝当前的一个单词
y0 拷贝的范围是当前光标处到行首
y^ 同上
y$ 拷贝的范围是当前光标处到行尾
yy 拷贝当前行
Y 同上
Nyy 从当前行开始拷贝 N 行
yf + 字符 复制从当前字符到指定字符
yG 拷贝当前行到文件尾
ygg 拷贝当前行到文件头
ggyG 复制整个文件
"+y 复制到系统剪切板
"+p 粘贴剪切板中的内容
Vim 还提供了基于底行命令模式的整行复制与移动命令:
:[range]co[py]{address}
:[range]t{address}
:[range]m[ove]{address}
命令 copy 可以简写成 :co
或者 :t
,命令 move 可以简写成 m
。示例:
:t5 拷贝当前行到第5行的下一行
:t. 拷贝当前行到光标下一行,相当于 `Yp` 或者 `yyp`
:t$ 拷贝当前行到文件最后一行
:50,100move200 移动50行到100行的内容到第200行后面
删除/修改
x
操作符用于删除单个字符或选中的文本,d
操作符用于删除单词、行、选中的文本等:
x 删除当前光标处字符
X 删除光标所在前一个字符
dw 删除一个单词
de 删除到本单词末尾
dE 删除到本单词末尾包括标点在内
db 删除到前一个单词
dB 删除到前一个单词包括标点在内
d0 删除光标位置到本行开头
d$ 删除从当前光标到行尾
D 同上
dd 删除一行
df + 字符 删除从当前字符到指定字符
# 删除括号或者引号中的内容
di(
di'
di"
# 包括括号或者引号一起删除
da(
da'
da"
c
操作符用于修改文本内容,即执行 c 操作时,会先删除选中的文本,然后再自动切换到插入模式:
cw 修改一个单词
c$ 修改从当前字符到行尾
cc 修改整行
C 修改当前光标至行尾
cf + 字符 修改从当前字符到指定字符
# 修改括号或者引号中的内容
ci(
ci'
ci"
# 包括括号或者引号一起修改
ca(
ca'
ca"
撤销/重做/合并行
u
撤销ctrl-r
重做
选中行,在执行 J
操作符可合并多行到一行,默认合并当前行与下一行。
范围
在使用 Vim 的一些操作时,无非就两步,即先选择要操作的内容,在执行相应的操作。要操作的内容即是这里所说的 范围(Ranges)。可以使用 :h cmdline-ranges
来查看有关命令操作范围的有关信息。
- 大多数命令都可以加一个数字,用于指明操作范围
- 范围可以是一个行号,用于指定某一行
- 范围也可以是一对通过
,
或;
分割的行号 - 大部分命令,默认只作用于当前行
:g[lobal]
默认会作用于所有行
范围的使用是十分直观的,以下是一些删除的例子(其中,:d
为 :delete
的缩写):
命令 | 操作范围 |
---|---|
:d |
当前行 |
:.d |
当前行 |
:1d |
第一行 |
:$d |
最后一行 |
:1,$d |
所有行 |
:%d |
所有行(这是 1,$ 的语法糖) |
:.,5d |
当前行至第 5 行 |
:,5d |
当前行至第 5 行 |
:,+3d |
当前行及接下来的 3 行 |
:1,+3d |
第一行至当前行再加 3 行 |
:,-3d |
当前行及向上的 3 行(Vim 会弹出提示信息,因为这是一个保留的范围) |
:3,'xdelete |
第三行至标注 为 x 的那一行 |
:/^foo/,$delete |
当前行以下,以字符 “foo” 开头的那一行至结尾 |
:/^foo/+1,$delete |
当前行以下,以字符 “foo” 开头的那一行的下一行至结尾 |
其中, .
表示当前行,$
表示结束,%
表示所有行,-
与 +
分别表示前后的偏移量。
;
也可以用于表示范围。区别在于,a,b
的 b 是以当前行作为参考的。而 a;b
的 b 是以 a 行作为参考的。比如说,现在的光标在第 5 行。这时 :1,+1d
会删除第 1 行至第 6 行,而 :1;+1d
会删除第 1 行和第 2 行。
搜索
文档内查找
*
向后查找光标当前所在单词#
向前查找光标当前所在单词g*
向后查找光标当前所在单词的字符序列,如当前单词为 foo 时,foobar 也会被找到g#
向前查找光标当前所在单词的字符序列/<pattern>
向后查找指定字符串?<pattern>
向前查找指定字符串
在执行查找命令后,按 n
会继续查找下一个,N
会继续查找上一个。注意,n 和 N 是有方向性的,若之前通过 * 查找,则 n 会继续向文档尾方向查找,N 向文档首方向;反之,若你通过 # 查找,则 n 指向文档首,N 指向文档尾。
在使用 /
或 ?
查找时,加入 \c
表示大小写不敏感查找,\C
表示大小写敏感查找。
行内查找
f<X>
当前行内向行尾方向查找并定位到字符 Xt<X>
当前行内向行尾方向查找并定位到字符 X 之前F<X>
当前行内向行首方向查找并定位到字符 XT<X>
当前行内向行首方向查找并定位到字符 X 之后
在执行查找命令后,;
继续向当前方向查找下一个字符,,
向当前相反方向查找下一个字符。
括号匹配查找
可以使用 %
对 ( 和 ),[ 和 ],{ 和 } 进行匹配查找,当光标位于其中一个 符号 上时,按下 %,光标会跳到与之匹配的另外一个符号上。
正则
元字符
. 匹配任意字符
[abc] 匹配方括号中的任意一个字符,可用-表示字符范围。如[a-z0-9]匹配小写字母和数字
[^abc] 匹配除方括号中字符之外的任意字符
\d 匹配阿拉伯数字,等同于[0-9]
\D 匹配阿拉伯数字之外的任意字符,等同于[^0-9]
\x 匹配十六进制数字,等同于[0-9A-Fa-f]
\X 匹配十六进制数字之外的任意字符,等同于[^0-9A-Fa-f]
\l 匹配[a-z]
\L 匹配[^a-z]
\u 匹配[A-Z]
\U 匹配[^A-Z]
\w 匹配单词字母,等同于[0-9A-Za-z_]
\W 匹配单词字母之外的任意字符,等同于[^0-9A-Za-z_]
\t 匹配<TAB>字符
\s 匹配空白字符,等同于[\t]
\S 匹配非空白字符,等同于[^\t]
表示数量的元字符
注意:下面除了 *
以外,其他都需要在前面加上 \
* 匹配 0-任意个
\+ 匹配 1-任意个
\? 匹配 0-1 个
\{n,m} 匹配 n-m 个
\{n} 匹配 n 个
\{n,} 匹配 n-任意个
\{,m} 匹配 0-m 个
表示位置的元字符
$ 匹配行尾
^ 匹配行首
\< 匹配单词词首
\> 匹配单词词尾
需转义的字符
\* 匹配* 字符
\. 匹配. 字符
\/ 匹配 / 字符
\\ 匹配 \ 字符
\[ 匹配 [ 字符
\] 匹配 ] 字符
在正则表达式中以 \(
和 \)
括起来的内容表示一个分组,在正则表达式后面使用的时候可以用 \1
、\2
等变量(1、2 表示分组序号)来访问 \(
和 \)
中的内容。如 \(foo\).*\1
可以配置 foo_bar_foo 等字符串。
需要同时查找多个字符串,可以使用 “或” 运算符,即 \|
。如 /foo\|bar
会同时查找 foo 和 bar 两个字符;再如 /end\(if\|while\|for\)
匹配 “endif”,”endwhile” 和 “endfor” 字符串。
在 Vim 中默认使用的搜索模式被称为 magic 模式。在这种模式下,Vim 自动为某些额外的符号赋予特殊含义,例如 .
、*
、[
等。这种模式的初衷是想能在 Vim 中更容易地构造简单的正则表达式,但它却没能为诸如 +
、?
、(
、)
、{
等符号赋予特殊含义,这些符号还必须经过转义才具有特殊含义。
Vim 还提供了 very magic 搜索模式 用于查找字符串,在这种模式下统一了所有特殊符号的规则:除下划线 _
、大小写字母以及数字 0 到 9 之外的所有字符都具有特殊含义。该模式使用 \v
开启,如:/\vend(if|while|for)
,这样,用于为特殊字符进行转义的反斜杠字符便可以去掉,使得匹配表达式的可读性更强。如该种模式下,便可以用 <
与 >
符号表示单词定界符,而无需转义。
此外,还有 very nomagic 搜索模式,在该模式中有且只有反斜杠 \
具有特殊意义,即消除了附加在 .
、*
以及 ?
等大多数字符上的特殊含义。也就是绝大多数字符都按原义进行查找匹配,该模式使用 \V
开启。如要查找 a.k.a. 字符串时,如果不使用 very nomagic 模式搜索,则其他的字符串也可能被找到,如 backward,除非使用转义 /a\.k\.a\.
。而使用 very nomagic 模式就要简单得多 /\Va.k.a.
。
`
替换
Vim 中的简单替换可以使用 r/R
、c/C
、s/S
等操作符:
r 替换当前字符
R 替换当前光标的字符直到退出替换模式(按ESC)
cw 替换当前单词
cc 替换当前行,相当于 S
C 替换当前位置到行尾,相当于 c$
此外,还可以使用 :s
(substitute)操作,配置范围、模式查找等实现更加强大的替换功能,其格式为:
[range]s/{pattern}/{string}/[flags]
flags 有如下四个选项
c
confirm,每次替换前询问e
error,不显示错误g
globle,不询问,整行替换。如果不加 g 选项,则只替换每行的第一个匹配到的字符串i
ignore,忽略大小写
可以同时使用多个 flag,如 cgi 表示不区分大小写,整行替换,替换前询问。示例:
:1,10s/from/to/g 表示在第1到第10行(包含第1,第10行)之间搜索替换
:10s/from/to/g 表示只在第10行搜索替换
:%s/from/to/g 表示在所有行中搜索替换
:1,$s/from/to/g 同上
:%s/\s+$//g 删除行尾空格
:%s/^\s*// 或 :%s/^ *// 删除行首多余空格
:%s/^$// 或 :g/^$/d 删除沒有內容的空行
:%s/^\s*$// 或 :g/^\s*$/d 删除包含有空格组成的空行
:%s/^[ |\t]*$// 或 :g/^[ |\t]*$/d 删除以空格或 tab 开头到结尾的空行
标记
标记 可以理解为 书签,在某处打上标记后,可以快速从别处跳转回来。标记可以分为三类:
- a-z 用户设置,仅对当前的一个文件生效,也就意味着只可以在当前文件中跳转
- A-Z 用户设置,全局标记,可以作用于不同文件。大写标注也称为「文件标注」。跳转时有可能会切换到另一个缓冲区
- 0-9 由 viminfo 记录,0 代表 viminfo 最后一次被写入的位置。实际使用中,就代表 Vim 进程最后一次结束的位置。1 代表 Vim 进程倒数第二次结束的位置,以此类推
定义一个标记用 m
操作符,如 ma
标记当前问题为 a 标记。在标记间跳转用 '
/ g'
或者 `
/ g`
加上标注名。单引号与倒引号的区别在与,单引号会跳转回被标记行的第一个非空字符,而倒引号会跳转回被标记行的被标记列。
还有一些其他的跳转方式:
'[ 与 `[ 上一次修改或复制的第一行或第一个字符
'] 与 `] 上一次修改或复制的最后一行或最后一个字符
'< 与 `< 上一次在可视模式下选取的第一行或第一个字符
'> 与 `> 上一次在可视模式下选取的最后一行或最后一个字符
'' 与 `' 上一次跳转之前的光标位置
'" 与 `" 上一次关闭当前缓冲区时的光标位置
'^ 与 `^ 上一次插入字符后的光标位置
'. 与 `. 上一次修改文本后的光标位置
'( 与 `( 当前句子的开头
') 与 `) 当前句子的结尾
'{ 与 `{ 当前段落的开头
'} 与 `} 当前段落的结尾
标记也可以搭配 范围 一起使用。如果在可视模式下选取一些文本,然后按下 :
,这时命令行会被填充为 :'<,'>
,这即表示在可视模式下选取的范围。
使用 :marks
可以查看当前所有的标记,使用 :h mark-motions
更多关于标记的帮助信息。
寄存器
寄存器主要用于存储文本内容,其为复制粘贴功能提供辅助。寄存器的访问和操作使用冒号 "
作为前缀,如 "ayy
表示复制当前行到 a 寄存器,"ap
表示粘贴寄存器中的内容。使用 :reg
可以查看当前所有寄存器中的内容,使用 :reg "{register_name}
可以查看指定寄存器的内容。
匿名寄存器(Unnamed): 保存最近一次的复制或删除操作 (d, c, s, x, y)。如果当前使用的 vim 版本支持剪切板,则可以将匿名寄存器定向到剪切板上,这样便可以与系统共享剪切板:
set clipboard=unnamed
编号寄存器(Numbered): 即以数字命令的寄存器,从 "0
到 "9
共 10 个。其中 "0
保存着最近一次复制的内容,"1
到"9
保存着删除掉的字符串。 删除操作符包括 s, c, d, x。 删除掉的字符串会被存到 “1 中,上次删除的则会被存到 “2 中,以此类推。
小删除寄存器(Small delete): 保存最近一次行内删除的内容,如 dw
删除一个词,d9l
删除 9 个字符,cb
向前更改一个词等。
命名寄存器(Named): 其有 "a
到 "z
共 26 个,这类寄存器只有在被指定时才会被定义和使用。其实在录制宏时,所有键盘操作会以字符串的形式存到寄存器中。需注意的是,寄存器名也可以为大写,当使用小写字母进行操作时会覆盖当前寄存器内容,而当使用大写字母进行操作时会追加当前寄存器内容。如 "Ayy
会复制当前行并追加到寄存器 a 中。
只读寄存器(Read-only): 共有 3 个只读寄存器,其值是由 Vim 提供,不允许改变:
".
:最近一次 insert 模式中插入的文本。注意.
命令用于重复上次操作,而".
用于存储上次插入"%
:当前文件名,不是全路径,也不是纯文件名,而是从当前 Vim 的工作目录到该文件的路径,即相对路径":
:最近一次底行命令模式下使用的命令。正如@a
可以执行"a
寄存器中的宏一样,@:
可以执行上次命令
交替文件寄存器(Alternate buffer): 交替文件寄存器 "#
存储着当前 Vim 窗口(Window)的交替文件。交替文件是指 Buffer 中的上一个文件,可通过 Ctrl+^
来切换交替文件与当前文件。
表达式寄存器(Expression): 表达式寄存器 "=
主要用于计算 Vim 脚本的返回值,并插入到文本中。当键入 "=
后光标会移动到命令行,此时可以输入任何 Vim 脚本的表达式,例如 3+2,按下回车并且 p 则会得到 5。这对于调试 Vim 脚本是非常有用的,比如调用一个函数看它是否有正确的返回值。
选择(Selection)和拖放(Drop)寄存器: 包括 "*
, "+
, 和 "~
,这三个寄存器的行为是和 GUI 相关的。
"*
和 "+
在 Mac 和 Windows 中,都是指系统剪切板(clipboard),例如 "*yy
即可复制当前行到剪切板。 以供其他程序中粘贴。其他程序中复制的内容也会被存储到这两个寄存器中。 在X11系统中(绝大多数带有桌面环境的Linux发行版),二者是有区别的:
"*
指 X11 中的 PRIMARY 选区,即鼠标选中区域。在桌面系统中可按鼠标中键粘贴。"+
指 X11 中的 CLIPBOARD 选区,即系统剪切板。在桌面系统中可按 Ctrl+V 粘贴。
拖放寄存器 "~
是只读的,当有文本拖拽到 Vim 时,被拖拽的文本被存储在 "~
中。Vim 默认的行为是将 "~
中内容插入到光标所在位置。
黑洞寄存器(Black hole): 所有删除或拷贝到黑洞寄存器 "_
的文本将会消失,这是为了在删除文本的同时不影响任何寄存器的值,其通常用于 Vim 脚本中。
搜索寄存器(Last search pattern): 搜索寄存器 "/
用于存储上一次搜索的关键词,即最近一次通过 /
、?
或 :global
等命令调用的匹配条件。该寄存器是可写的,例如: let @/ = "harttle"
将会把 “harttle” 写入该寄存器。下次搜索时不输入搜索词直接回车便会搜索 “harttle”。
宏
在 Vim 中可以录制一系列按键动作,并把他们存储到寄存器中,这便是 宏。宏是一系列操作的集合,它可以将一些复杂的操作进行记录,之后可以进行回放。
操作符 q
用于开启或结束宏录制,按 q{register}
开始进入录制,然后再按 q
可结束录制。如果要对宏进行回放,按 @{register}
。
示例一,在行末加分号,命令为:
qa
$a;<Esc>j$,
q
命令的含义是:开启宏录制,并记录到寄存器 a 中,先移动到行尾,然后在行尾插入分号,接着退到普通模式,再把光标移动到下一行的末尾,最后结束宏录制。录制结束后,输入 @a
便会执行宏中的操作,5@m
表示重复执行 5 次宏操作。
示例二,从 1 到 100,每行 +1,首先在第一行插入 1,然后光标定位到第一行的 “1” 上,执行宏录制:
qb
yyp<Ctrl>a
q
命令的含义是:开始录制宏到寄存器 b 中,yy
复制当前行,p
粘贴到下一下, <Ctrl>a
让当前光标所在数字加 1。然后执行 98@b
将宏回访 98 遍即可实现将数字加到 100。
其他
插入计算结果
在插入模式下,输入 ctrl-r =
,然后输入表达式,就能在光标处得到计算结果。
保存无权限的只读文件
如果打开了一些没有权限编辑的只读文件,并修改了内容,且希望对修改进行保存时,可以用如下命令(前提是当前用户有 sudo 权限):
:w !sudo tee %
高亮普通文件
有的文件可能没有后缀(扩展名),Vim 无法识别文件类型,所以也无法进行语法高亮,此时可以手动设置文件的类型,以开启语法高亮。如设置文件类型为 shell 脚本类型:
:set filetype=sh
编辑远程文件
Vim 内置的插件 netrw 支持对远程文件的编辑。它的原理是将远程的文件通过 scp 复制到本地的临时文件中,再用这个文件打开一个缓冲区,然后在保存时再将文件复制回远程位置。以下命令列举在本地打开 SSH 远程服务器上文件的方式:
:e scp://user@remotehost/.vimrc
:e scp://user@remotehost/~/.vimrc
:e scp://user@remotehost//etc/passwd
也可以配置 ~/.ssh/config
文件,使得命令更加简单,如 ~/.ssh/config 存在如下配置:
Host test
HostName test.site.com
Port 23456
User test
那么编辑文件的命令就可以变得很简单:
:e scp://test/.vimrc
查看安装的所有脚本
:scriptnames
有用的快捷键
K 打开光标所在词的 manpage
. 重复上一次的操作,如 dd 删除一行后,. 命令可继续执行删除