Vim技巧
- 一、优化重复操作
-
- [1.1、 . 命令](#1.1、 . 命令)
- [1.2、* 命令](#1.2、* 命令)
- 1.3、重复修改示例
- 二、删除单词(daw)
- 三、对数字做算数运算
- 四、操作符与动作
- 五、插入模式
- 六、替换模式
- 7、可视模式
- 8、命令行模式
一、优化重复操作
1.1、 . 命令
.
命令可以让我们重复上次的修改。"上次修改"可以指很多东西,一次修改的单位可以是字符、整行,甚至是整个文件。
从进入插入模式的那一刻起(例如,输入 i
) ,直到返回普通模式时为止 (输入<Esc>
) , Vim 会记录每一个按键操作。 做出这样一个修改后再用 .
命令的话,它将会重新执行所有这些按键操作。
bash
# 文档a.txt内容如下
Line one
Line two
Line three
Line four
# >G 命令会增加从当前行到文档末尾处的缩进层级。
# 如果我们在此命令后使用 . 命令,那么"重复上次修改"会让 Vim 增加从当前行到文档末尾的缩进层级。
# 命令如下
>G j. j. j.
# 最后文档如下
Line one
Line two
Line three
Line four
1.2、* 命令
*
命令可以查找当前光标下的单词,等同于/xxxx
。
bash
Line one
Line two
Line three
Line four
把光标移到单词"Line"上,然后使用 *
命令对它进行查找,这会产生两个结果:
- 一是光标会跳到下一个匹配项上
- 二是所有出现这个词的地方都会被高亮显示出来
如果你并没有看到高亮,试着运行一下 :set hls
。执行过一次查找"Line"的命令后,现在我们只需按 n 键就可以跳到下一个匹配项。
1.3、重复修改示例
bash
# a.txt内容如下
Line one
Line two
Line three
Line four
# 将所有Line替换为XXX
# 1. 光标放到第一个Line上,*
# 2. cw 删除Line,输入 XXX,<ESC>
# 3. 按n跳转到下一个匹配的Line,按.重复修改
# 即 * cw XXX <ESC> n. n. n.
二、删除单词(daw)
bash
# 光标位于行尾处的字符"h"上,而我们想要删除单词"nigh"
The end is nigh
反向删除:
按 db
命令删除从光标起始位置到单词开头的内容,但会原封未动地留下最后一个字符 "h" ,再按一下 x
键就可以删除这个捣乱的字符。
正向删除:
先用 b
命令把光标移到单词的开头,移动好后,就可以用一个 dw
命令删掉整个单词。
删除整个单词:
可以使用更为精准的 aw
文本对象 (text object) , 而不是用动作命令。
使用daw
一次删除整个单词,可以把 daw 命令解读为"delete a word" ,这样比较容易记忆。
三、对数字做算数运算
<C-a>
和 <C-x>
命令分别对数字执行加和减操作。在不带次数执行时,它们会逐个加减,但如果带一个次数前缀,那么就可以用它们加减任意整数。
如果光标不在数字上
<C-a>
命令会"把当前光标之上或之后的数值加上 [count]"。因此,如果光标不在数字上,那么<C-a>
命令将在当前行正向查找一个数字,如果找到了,它就径直跳到那里。我们可以利用这一点简化操作。
bash
# 假设光标位于首字符
This is 2 times;
This is 3 times;
# 按下 10<C-a> 后
This is 12 times;
This is 3 times;
四、操作符与动作
操作符 + 动作命令 = 操作
d{motion}
命令可以对一个字符(dl
)、一个完整单词(daw
)或一整个段落(dap
)进行操作,它作用的范围由动作命令决定。c{motion}
、y{motion}
以及其他一些命令也类似,它们被统称为操作符(operator)。你可以用:h operator
来查阅完整的列表,下表总结了一些比较常见的操作符。
操作符 | 动作 |
---|---|
c |
修改 |
d |
删除 |
y |
复制到寄存器 |
g~ |
反转大小写 |
gu |
转换为小写 |
gU |
转换为大写 |
> |
增加缩进 |
< |
减小缩进 |
= |
自动缩进 |
! |
使用外部程序过滤{motion}所跨越的行 |
操作符与动作命令的结合形成了一种语法。这种语法的第一条规则很简单,即一个操作由一个操作符,后面跟一个动作命令组成。假如我们已经知道如何用 daw
删除一个单词,然后又学到 gU
命令。它也是个操作符,所以我们可以用 gUaw
把当前单词转换成大写形式。如果我们的词汇进一步扩充,学会了作用于段落的 ap
动作命令,就会发现我们可以进行两个新的操作:用 dap
删除整个段落,或者用 gUap
把整段文字转换为大写。
Vim 的语法只有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行。所以 dd
删除当前行,而 >>
缩进当前行。gU
命令是一种特殊情况,我们既可以用 gUgU
,也可以用简化版的 gUU
来使它作用于当前行。
五、插入模式
5.1、插入模式下删除
在插入模式下,除了退格键可以删除。另外,我们还可以用下面这些组合键:
按键操作 | 用途 |
---|---|
<C-h> |
删除前一个字符(同退格键) |
<C-w> |
删除前一个单词 |
<C-u> |
删至行首 |
5.2、返回普通模式
在插入模式下,除了<Esc>
键可以返回普通模式。另外,我们还可以用下面这些组合键:
按键操作 | 用途 |
---|---|
<Esc> |
切换到普通模式 |
<C-[> |
切换到普通模式 |
<C-o> |
切换到插入-普通模式 |
5.3、插入-普通模式
插入-普通模式是普通模式的一个特例,它能让我们执行一次普遍模式命令。在此模式中,我们可以执行一个普通模式命令,执行完后,马上就又返回到插入模式。要从插入模式切换到插入-普通模式,可以按 <C-o>
。
在当前行正好处于窗口顶部或底部时,有时我会滚动一下屏幕,以便看到更多的上下文。用 zz
命令可以重绘屏幕,并把当前行显示在窗口正中,这样就能够阅读当前行之上及之下的半屏内容。我常常会键入 <C-o>zz
,在插入-普通模式中触发这条命令。此操作完成后就会直接回到插入模式,因此我可以不受中断地继续打字。
5.4、不离开插入模式,粘贴寄存器中的文本
我们想把本书的书名插到最后一行,以补全该行。由于书名在第一行的开头已经出现过了,我们将把它复制到一个寄存器中,然后在插入模式中把它添加到第二行结尾。
按键操作 | 缓冲区内容 |
---|---|
yt, |
P ractical Vim, by Drew Neil Read Drew Neil's |
jA空格 |
Practical Vim, by Drew Neil Read Drew Neil's |
<C-r>0 |
Practical Vim, by Drew Neil Read Drew Neil's Practical Vim`` |
.<Esc> |
Practical Vim, by Drew Neil Read Drew Neil's Practical Vim. |
yt,
命令把"Practical Vim"复制到复制专用寄存器中,然后我们在插入模式中,按 <C-r>0
把刚才复制的文本粘贴到光
标所在位置。
对面向字符的寄存器使用
<C-r>{register}
命令,其中{register}是我们想要插入的寄存器的名字。
5.4、表达式寄存器
大部分的 Vim 寄存器中保存的都是文本,要么是一个字符串,要么是若干行的文本。删除及复制命令允许我们把文本保存到寄存器中,而粘贴命令则允许我们把寄存器中的内容插入到文档里。
不过表达式寄存器则是个另类,它可以用来执行一段 Vim 脚本,并返回其结果。可以用 =
符号指明使用表达式寄存器。在插入模式中,输入 <C-r>=
就可以访问这一寄存器。这条命令会在屏幕的下方显示一个提示符,我们可以在其后输入
要执行的表达式。输入表达式后敲一下 <CR>
, Vim 就会把执行的结果插入到文档的当前位置了。
假设我们刚输入完下列内容:
bash
6 chairs, each costing $35, totals $
我们想算一下总价,不过没必要找个信封在背面做演算,Vim 可以帮我们做这件事,我们甚至连插入模式都不用退出。
按键操作 | 缓冲区内容 |
---|---|
A |
6 chairs, each costing 35, totals |
<C-r>= 6*35<CR> |
6 chairs, each costing 35, totals 210 |
5.5、用字符编码插入字符
Vim 可以用字符编码(Character Code)插入任意字符。使用此功能可以很方便地输入键盘上找不到的符号。
只要知道某个字符的编码,就可以让 Vim 插入该字符,我们可以用这种方式插入任意字符。要根据字符编码插入字符,只需在插入模式中输入 <C-v>{code}
即可,其中{code}是要插入字符的编码。
Vim 所接受的字符编码共包含 3 位数字。例如,假设我们想插入大写字母"A",它的字符编码是 65,因此我们需要输入 <C-v>065
。
然而,如果我们想插入一个编码超过 3 位数的字符该怎么办?比方说,Unicode基本多文种平面 (Unicode Basic Multilingual Plane) 的地址空间最大会有 65535 个字符。解决方法是可以用 4 位十六进制编码来输入这些字符,即输入<C-v>u{1234}
(注意数字前的 u ) 。假设我们想插入字符编码为 00bf
的反转问号( "¿
" ) ,只需在插入模式中输入 <C-v>u00bf
即可。
如果你想知道文档中任意字符的编码,只需把光标移到它上面并按 ga
命令,然后屏幕下方就会显示出一条消息,分别以十进制和十六进制的形式显示出其字符编码。
另外,如果 <C-v>
命令后面跟一个非数字键,它会插入这个按键本身所代表的字符。例如,如果启用了'expandtab' 选项,那么按 <Tab>
键将会插入空格而不是制表符。然而,按 <C-v><Tab>
则会一直插入制表符,不管'expandtab' 选项激活与否。
按键操作 | 用途 |
---|---|
ga |
查看编码 |
<C-v>{123} |
以十进制字符编码插入字符 |
<C-v>u{1234} |
以十六进制字符编码插入字符 |
<C-v>{nondigit} |
按原义插入非数字字符 |
<C-k>{char1}{char2} |
插入以二合字母{char1}{char2}表示的字符 |
六、替换模式
在替换模式中输入会替换文档中的已有文本,除此之外,该模式与插入模式完全相同。
命令 | 用途 |
---|---|
R |
普通模式进入替换模式 |
r{char} /gr{char} |
单次版本的替换模式及虚拟替换模式,允许我们覆盖一个字符,之后马上又回到普通模式 |
假设有如下一段文本:
bash
Typing in Insert mode extends the line. But in Replace mode
the line length doesn't change.
我们想把这两个单独的句子合并成一句话,为此,需要把句号改成逗号,并将单词"But"中的"B"改为小写。
按键操作 | 缓冲区内容 |
---|---|
{start} |
T yping in Insert mode extends the line. But in Replace mode the line length doesn't change. |
f. |
Typing in Insert mode extends the line. But in Replace mode the line length doesn't change. |
R,空格b<Esc> |
Typing in Insert mode extends the line. b ut in Replace mode the line length doesn't change. |
7、可视模式
可视模式允许我们选中一个文本区域并在其上操作。我们仍可以把 h、j、k及 l当成光标键使用;也可以用 f{char} 跳到当前行的某个字符上,然后用 ; 和 , 命令相应地正向或反向重复此跳转;甚至还可以用查找命令(以及 n / N 命令)跳转到匹配指定模式的地方。每次在可视模式中移动光标,都会改变高亮选区的边界。
7.1、选择高亮区域(三种子模式)
激活可视模式:
命令 | 用途 |
---|---|
v |
激活面向字符的可视模式 |
V |
激活面向行的可视模式 |
<C-v> |
激活面向列块的可视模式 |
gv |
重选上次的高亮选区 |
可视模式间切换:
按键操作 | 用途 |
---|---|
<Esc> / <C-[> |
回到普通模式 |
v /V /C-v |
切换到普通模式(在对应的面向字符可视模式、面向行的可视模式或面向列块的可视模式中使用时) |
v |
切换到面向字符的可视模式 |
V |
切换到面向行的可视模式 |
<C-v> |
切换到面向列块的可视模式 |
o |
切换高亮区的活动端 |
切换选区的活动端:
高亮选区的范围由其两个端点界定。其中一端固定,而另一端可以随光标自由移动,我们可以用 o
键来切换其活动的端点。在定义选区时,如果定义到一半时,才发现选区开始的位置不对,此时用这个键会很方便,我们用不着退出可视模式再
从头开始,只需按一下 o,然后重新调整选区的边界即可。下面的操作对此功能进行了演示:
按键操作 | 缓冲区内容 |
---|---|
{start} |
Select from here to h ere. |
vbb |
Select from h ere to here. |
o |
Select from here to h ere. |
e |
Select from here to here . |
7.2、重复执行面向行的可视命令
假设有一段 Python 代码的缩进有些问题,如下所示:
python
def fib(n):
a, b = 0, 1
while a < n:
print a,
a, b = b, a+b
fib(42)
这段代码的每级缩进使用 4 个空格,首先我们得对 Vim 进行配置,使之符合此缩要想让 < 和 > 命令正常工作,我们需要把 'shiftwidth' 及 'softtabstop'进风格。
bash
:set shiftwidth=4 softtabstop=4 expandtab
python
# {start}
def fib(n):
a, b = 0, 1
while a < n:
print a, # 光标位于p
a, b = b, a+b
fib(42)
# Vj
def fib(n):
a, b = 0, 1
while a < n:
print a, # 选中此行
a, b = b, a+b # 选中此行
fib(42)
# >. 重复缩进
def fib(n):
a, b = 0, 1
while a < n:
print a,
a, b = b, a+b
fib(42)
7.3、面向块的可视模式编辑
假设有如下一个纯文本表格:
bash
Chapter Page
Normal mode 15
Insert mode 31
Visual mode 44
我们想用管道符画一条竖线来隔开这两列文本,使之看起来更像一个表格。但是在此之前,要先减少两列之间的间隔,使它们不要分得这么开。用面向列块的可视模式可以完成这两处修改,
bash
{start} # 光标放在Chapter和Page中间
<C-v>3j # 向下选3行
x... # 删除并重复3次
gv # 再次选区高亮区域
r| # 替换模式下替换为|
yyp # 光标在Chapter行,复制并粘贴该行
Vr- # 切换到行可视模式,替换为-
# 结果为
Chapter | Page
--------------------
Normal mode | 15
Insert mode | 31
Visual mode | 44
7.4、在长短不一的高亮块后添加文本
js
var foo = 1
var bar = 'a'
var foobar = foo + bar
这段代码有连续 3 行,每行的长度各不相同,而我们想在每行结尾添加一个分号。
bash
{start} # 开始,光标在首行1位置上
<C-v>jj$ #开启块可视模式,选中到行尾
A; # 尾部添加;
<Esc> # 退出
确定好选区后,用 A 命令就可以在每行的结尾添加内容。此命令让我们进入插入模式,且使光标停留在顶行。处于插入模式期间,任何输入的内容只出现在顶行,然而一旦返回到普通模式,这些修改就会被扩散到其余选中的行上。
8、命令行模式
命令行模式会提示我们输入一条 Ex 命令、一个查找模式,或一个表达式。在按下 :
键时,Vim 会切换到命令行模式。这个模式和 shell 下的命令行有些类似, 我们可以输入一条命令, 然后按 <CR>
执行它。 在任意时刻, 我们都可以按 <Esc>
键从命令行模式切换回普通模式。
操作缓冲区文本的Ex命令:
命令 | 用途 |
---|---|
:[range]delete [x] |
删除指定范围内的行[到寄存器 x中] |
:[range]yank [x] |
复制指定范围的行[到寄存器 x中] |
:[line]put [x] |
在指定行后粘贴寄存器 x中的内容 |
:[range]copy {address} |
把指定范围内的行拷贝到{address} 所指定的行之下 |
:[range]move {address} |
把指定范围内的行移动到 {address} 所指定的行之下 |
:[range]join |
连接指定范围内的行 |
:[range]normal {commands} |
对指定范围内的每一行执行普通模式命令 {commands} |
:[range]substitute/{pattern}/{string}/[flags] |
把指定范围内出现{pattern}的地方替换为{string} |
:[range]global/{pattern}/[cmd] |
对指定范围内匹配{{pattern}的所有行,在其上执行Ex 命令{cmd} |
8.1、选定操作范围
很多 Ex 命令可以用 [range]
指定要操作的范围。我们可以用行号、位置标记或是查找模式来指定范围的开始位置及结束位置。
html
<!DOCTYPE html>
<html>
<head><title>Practical Vim</title></head>
<body><h1>Practical Vim</h1></body>
</html>
我们将使用:print
命令作为演示。 这条命令只是简单地在 Vim 命令行下方回显指定行的内容,它不产生什么实际影响,不过可以用它来说明一个范围由哪些行构成。当然,你可以试着把以下示例中的:print
换成诸如:delete
、:join
、:substitute
或:normal
这样的命令,这样就能真切地感受到 Ex 命令是多么有用。
用行号作为地址:
bash
# 如果输入一条只包含数字的 Ex 命令,那么 Vim 会把这个数字解析成一个地址,并把光标移动到该数字所指定的行上。
:1
:p
# 或
:1p
#输出
1 <!DOCTYPE html>
用地址指定一个范围:
bash
# 语法 :{start},{end}
# 打印2到5行
:2,5p
# 输出
2 <html>
3 <head><title>Practical Vim</title></head>
4 <body><h1>Practical Vim</h1></body>
5 </html>
# 当前行到最后一行
.,$p
# 全文
%p
# 等价于 1,$p
用高亮选区指定范围:
我们也可以用高亮选区选定一个范围,而不是用数字指定。如果我们先执行 2G
,再跟着执行 VG
,就会选中如下一个高亮选区:

如果现在按下 :
键,命令行上就会预先填充一个范围 :'<,'>
。这个范围看起来有点晦涩难懂,不过你可以简单地把它理解为一个代表高亮选区的范围。接下来我们就可以输入一条 Ex 命令,使它在每个被选中的行上执行:
bash
:'<,'>p
用模式指定范围:
Vim 也接受以模式作为一条 Ex 命令的地址,如下所示:
bash
:/<html>/,/<\/html>/p
# 输出
2 <html>
3 <head><title>Practical Vim</title></head>
4 <body><h1>Practical Vim</h1></body>
5 </html>
这个范围看起来比较复杂,但实际上它符合范围的一般形式:{start},{end}
。在本例中, {start}
地址是模式 /<html>/
,而 {end}
地址是 /<\/html>/
。换句话说,这个范围由 <html>
开标签所在的行开始,到对应闭标签所在的行结束。
用偏移对地址进行修正:
假设我们想对位于<html></html>
之间的每一行都运行一条 Ex 命令,但是不想包括 <html>
及 </html>
标签所在的行,那么可以为之加上偏移:
bash
# 语法 :{address}+n
:/<html>/+1,/<\/html>/-1p
#输出
3 <head><title>Practical Vim</title></head>
4 <body><h1>Practical Vim</h1></body>
总结:
符号 | 地址 |
---|---|
1 |
文件的第一行 |
$ |
文件的最后一行 |
0 |
虚拟行,位于文件第一行上方 |
. |
光标所在行 |
'm |
包含位置标记 m的行 |
'< |
高亮选区的起始行 |
'> |
高亮选区的结束行 |
% |
整个文件(:1,$ 的简写形式) |
8.2、复制和移动(:t和:m)
:copy
命令(及其简写形式:t
)让我们可以把一行或多行从文档的一部分复制到另一部分:move
命令(及其简写形式:m
)则可以让我们把一行或多行移到文档的其他地方
bash
Shopping list
Hardware Store
Buy new hammer
Beauty Parlor
Buy nail polish remover
Buy nails
用:t
命令复制行:
bash
# 语法
:[range]copy {address}
这个购物清单还没完成,我们也要在五金商店(hardware store)买些钉子(nails) 。为完成这个清单,我们将重用文件的最后一行,即在"Hardware Store"下面为之创建一份副本。
bash
{start} #开始,光标位于第二行H位置
:6t. # 复制第6行,并粘贴到当前行下
# 结果如下
1 Shopping list
2 Hardware Store
3 Buy nails
4 Buy new hammer
5 Beauty Parlor
6 Buy nail polish remover
7 Buy nails
应用实例:
命令 | 用途 |
---|---|
:6t. |
把第 6行复制到当前行下方 |
:t6 |
把当前行复制到第 6行下方 |
:t. |
为当前行创建一个副本(类似于普通模式下的 yyp) |
:t$ |
把当前行复制到文本结尾 |
:'<,'>t0 |
把高亮选中的行复制到文件开头 |
用:m
命令移动行:
bash
# 语法
:[range]move {address}
假设我们想把 Hardware Store 一节移到 Beauty Parlor 一节的下方,用 :move 就可以实现这一点:
bash
{start} # 开始,光标位于第2行H位置
Vjj # 进入列视图模式,并向下选中2行
:'<,'>m$ # 将选中高亮区域移动到最后一行后面
# 结果
1 Shopping list
2 Beauty Parlor
3 Buy nail polish remover
4 Buy nails
5 Hardware Store
6 Buy nails
7 Buy new hammer
8.3、在指定范围上执行普通模式命令
如果想在一系列连续行上执行一条普通模式命令,我们可以用 :normal
命令。此命令在与.
命令或宏结合使用时,我们只需花费很少的努力就能完成大量重复性任务。
们将在下面文件的每行后都添加一个分号,以此作为演示。
js
var foo = 1
var bar = 'a'
var baz = 'z'
var foobar = foo + bar
var foobarbaz = foo + bar + baz
bash
{start} # 光标位于第一行v位置
A;<Esc> # 移动行尾进入插入模式输入;然后返回普通模式
jVG # 移动到下一行,进入行视图模式,选中到文档尾部
:'<,'>normal . #进入命令模式,normal命令执行.
# 结果
1 var foo = 1;
2 var bar = 'a';
3 var baz = 'z';
4 var foobar = foo + bar;
5 var foobarbaz = foo + bar + baz;
命令模式中,可以使用如下命令完成相同操作:
bash
:%normal A;
8.4、重复上次的Ex命令
.
命令可以重复上次的普通模式命令。然而,如果想重复上次的 Ex 命令的话,我们得使用 @:
才行。
例如,下面两条命令在遍历缓冲区列表的条目时非常有用,用 :bn[ext]
可以在列表中逐项正向移动,而 :bp[revious]
命令则进行反向移动 。 假设缓冲区列表中有大约十几个条目, 而我们打算逐个查看每个缓冲区,因此可以输入一次下面的命令:
bash
:bnext
然后再用 重复执行此命令。
8.5、自动补全Ex命令
如同在 shell 中一样,在命令行上也可以用 <Tab>
键自动补全命令。
Vim 在选取 Tab 补全的补全项时非常智能,它会检查命令行上已经输入的上下文,然后再构建合适的补全列表。例如,可以这样输入:
bash
:col<C-d>
colder colorscheme
<C-d>
命令会让 Vim 显示可用的补全列表。另外,如果
我们多次按 <Tab>
键的话,命令行上会依次显示 colder、colorscheme,然后再回到最初的 col,如此循环往复。要想反向遍历补全列表,可以按 <S-Tab>
。
8.6、把当前单词插入到命令行
即使是在命令行模式下, Vim 也始终知道光标位于何处以及哪个分割窗口处于活动状态。为节省时间,我们可以把活动窗口中的当前单词(或字串)插入到命令行中。
在 Vim 的命令行下, <C-r><C-w>
映射项会复制光标下的单词并把它插入到命令行中。我们可以利用这一功能减少击键的次数。
假设我们想把下面这段代码中的变量 tally重命名为 counter:
js
var tally;
for (tally=1; tally <= 10; tally++) {
// do something with tally
};
把光标移到单词 tally上后,用 *
命令就可以查找它出现的每处地方(* 命令等效于输入/\<<C-r><C-w>\><CR>
序列。
bash
{start} # 开始光标位于第一行t位置
* # 查找出所有tally
cwcounter<Esc> #cw命令删除tally并进入插入模式tally,然后返回普通模式
:%s//<C-r><C-w>/g # 然 后 , 我 们 将 用 :substitute 命 令 完 成 其 余 的 修 改 。 由 于 光 标 已 经 在 单 词"counter"上了,因此我们无需再次输入它,而是直接用 <C-r><C-w>映射项把它插入到替换域
8.7、回溯历史命令
Vim 会记录命令行模式中执行过的命令,并提供了两种方式回溯这些命令,用光标键回滚之前的命令或调出命令行窗口查看先前的命令。
先按 : 键切换到命令行模式,在保持提示符为空的情况下按 <Up>
键,此时最后执行的那条 Ex 命令就会被填充到命令行上。再接着按 <Up>
键的话,就可以回到更早的 Ex 历史命令;按 <Down>
键的话,则会沿相反方向滚动。
Vim 缺省会记录最后 20 条命令,对内存越发便宜的现代计算机来说,保存更多历史命令只是小菜一碟,因此我们可以修改 'history' 选项,以提高其保存的上限。
你可以试着把下面这行内容加入 vimrc 文件:
bash
set history=200
8.8、运行Shell命令
不用离开 Vim 就能方便地调用外部程序。更棒的是,我们还可以把缓冲区的内容作为标准输入发送给一个外部命令, 或是把外部命令的标准输出导入到缓冲区里。
在 Vim 的命令行模式中,给命令加一个叹号前缀就可以调用外部程序。例如,如果想查看当前目录的内容,可以运行下面的命令:
bash
:!ls
在 Vim 的命令行中,符号 %
代表当前文件名 。在运行那些操作当前文件的外部命令时,我们可以使用它。例如,如果我们正在编辑某个 脚本 文件,那么可以用下面的方式执行此文件:
bash
:!sh %
:!{cmd}
这种语法适用于执行一次性命令,但是如果想在 shell 中执行几条命令要怎么做?对这种情况,可以执行 Vim 的 :shell
命令来启动一个交互的 shell 会话。用 exit 命令可以退出此 shell 并返回 Vim。
把缓冲区内容作为标准输入或输出:
在用 :!{cmd}
时,Vim 会回显 {cmd} 命令的输出。如果命令的输出很少或没有输出,这工作得很好;但如果命令会产生大量输出,这样回显用处不大。另外一种做法是我们可以用 :read !{cmd}
命令,把 {cmd} 命令的输出读入当前缓冲区中。
:read !{cmd}
命令让我们把命令的标准输出重定向到缓冲区。正如你所期望的一样, :write !{cmd}
做相反的事。它把缓冲区内容作为指定 {cmd} 的标准输入。
使用外部命令过滤缓冲区内容:
当给定一个范围时,:!{cmd}
命令就具有了不同的含义。由[range]所指定的行会传给{cmd} 作为标准输入,然后又会用 {cmd} 的输出覆盖 [range]内原本的内容。
换一种说法就是 [range] 内的文本会被指定的 {cmd} 进行过滤。Vim 把过滤器定义为 "一个由标准输入读取文本, 并对其进行某种形式的修改后输出到标准输出的程序" 。
作为演示,我们将用外部的 sort 命令对下列 CSV 文件中的记录进行排序:
bash
first name,last name,email
john,smith,[email protected]
drew,neil,[email protected]
jane,doe,[email protected]
我们想基于第二个字段"姓氏"来重排这些记录。我们可以用 -t','
参数告诉sort 命令,这些记录以逗号分隔,然后再用 -k2
参数指定按第二个字段进行排序。
因为文件的第一行是标题信息,我们想把它们保留在文件顶部,因此需要用范围 :2,$
把它排除在排序范围之外。下列命令将完成我们想要的功能:
bash
:2,$!sort -t',' -k2
#结果:
1 first name,last name,email
2 jane,doe,[email protected]
3 drew,neil,[email protected]
4 john,smith,[email protected]
总结:
命令 | 用途 |
---|---|
:shell |
启动一个 shell (输入 exit返回 Vim) |
:!{cmd} |
在 shell 中执行 {cmd} |
:read !{cmd} |
在 shell 中执行 {cmd} ,并把其标准输出插入到光标下方 |
:[range]write !{cmd} |
在 shell 中执行 {cmd} ,以 [range] 作为其标准输入 |
:[range]!{filter} |
使用外部程序 {filter} 过滤指定的 [range] |