vim 在 vi 的基础上增加了“无穷步的回退”、“无穷步的重做”。
vim 的四种模式:
一开始进入的就是正常模式。
从其他模式中返回正常模式:
Esc 或 ctrl+[
h 左
j 下
k 上
l 右
3h 往左移动3次光标(不跨行)
3j 往下移动3次光标
3k 往上移动3次光标
3l 往右移动3次光标
b 移动到单词首(如果已经在单词首,则移动到上一个单词首,可跨行)
e 移动到单词尾(如果已经在单词尾,则移动到下一个单词尾,可跨行)
w 移动到下一个单词的开头
ge 移动到上一个单词的结尾
$ 移动到行尾
3$ 移动到所在行往下2行(若所在行为第n行,则移动到n+2行)的行尾
^ 移动到行首第一个非空字符
0 移动到行首
fa 移动到该行光标所在处向后最近的一个a处(区分大小写)
2fa 相当于操作fa两次
Fa 移动到该行光标所在处向前最近的一个a处(区分大小写)
3Fa 相当于操作Fa三次
fa(或Fa)后,可以用分号;来跳到下一个(或上一个)a
ctrl+y 向上滚动一行(光标不移动)
ctrl+e 向下滚动一行(光标不移动)
ctrl+u 向上滚动半屏(光标会移动到翻页后的行首)up
ctrl+d 向下滚动半屏(光标会移动到翻页后的行首)down
ctrl+b 向上滚动一屏(光标会移动到翻页后的行首)back
ctrl+f 向下滚动一屏(光标会移动到翻页后的行首)forward
H 移动到当前屏幕的最上方一行行首非空字符
L 移动到当前屏幕的最下方一行行首非空字符
M 移动到当前屏幕的中间一行的行首非空字符
{ 移动到段落首部,移动到上一个段落首部
} 移动到段落尾部,移动到下一个段落尾部
gg 或 [[ 或1G 移动到第一行行首非空字符
G 或 ]] 移动到最后一行行首非空字符
3G 移动到第3行行首非空字符
# 字符
yl 复制光标所在字符
yh 复制光标前一个字符
2yl 或 y2l 复制光标所在字符以及下一个字符(共2个字符,不可跨行,若光标所在是行内最后一个字符,则只复制该字符)
2yh 或 y2h 复制光标前两个字符(共2个字符,不可跨行,若行内光标前已经没有字符,则没有复制内容,光标前还有一个字符,则只复制该字符)
yfr 复制光标当前字符(含)直到后方第一个r(含)的范围
yFd 复制光标所在位置的前方第一个d(含)到光标前一个字符的范围
# 单词
yw 复制单词从光标处(含)到单词尾内容
yb 复制单词从光标前到单词首内容
y2w 复制单词从光标处(含)到单词尾,以及下一个单词(可跨行)的内容
y2b 复制单词从光标前到单词首的内容,以及上一个单词(可跨行)的内容
yaw 复制光标所在的单词
# 行
y$ 复制光标所在位置到行尾的内容
y^ (或y0) 复制光标前位置到行首的内容
yy(或大写Y) 复制光标所在整行
y下方向键(或yj) 复制光标所在行及其下1行(共2行)
3y下方向键(或2yj) 复制光标所在行及其下3行(共4行)
y上方向键(或yk) 复制光标所在行及其上1行(共2行)
3y上方向键(或3yk) 复制光标所在行及其上3行(共4行)
3yy(或y3y) 复制光标所在行及其下2行(共3行)
ynG 复制光标所在行到第n行(范围,双闭区间,无论第n行在光标所在行的上方或下方),原理是“nG”是移动到第n行。
# 文档
yG 复制光标所在行及到文档尾的所有行
y1G 或 ygg 复制光标所在行及到文档首的所有行
p(小写p)
复制的是光标所在位置到行尾、光标前到行首的内容、单词截取内容(可跨行):在光标的后方插入复制内容
复制的是整行:在光标下方插入复制行
复制的是多行:在光标下方插入复制行
P(大写P)
p小写p代表贴至游标后(下)。
P大写P代表贴至游标前(上)。
# 多次粘贴
10p # 粘贴 10 次内容
d
d^ 剪切光标前到行首的内容
d$ 或 D 剪切光标所在字符(含)到行尾的内容,注意与Y的用法区别,Y是直接复制整行,D并非剪切整行
dd 剪切光标所在行
其他命令搭配使用和复制y是一样的
实际效果就是剪切的同时,从正常模式进入插入模式。
cl 或 c空格 剪切光标所在字符
c$ 或 C 剪切光标所在字符(含)到行尾的内容,注意与Y的用法区别,Y是直接复制整行,C并非剪切整行
基本就是和剪切命令的搭配一样,只不过是之后会进入插入模式
x 删除光标所在的单个字符
2x 删除光标所在字符以及下一个字符(共2个字符,不跨行)
X (大写X)删除光标前的单个字符(不含guang)
2X (大写X)删除光标前的2个字符(不跨行)
J 删除光标所在行的下一行换行符,替换成一个空格
r 对光标所在字符进行替换,按下要替换为的单个字符后,会自动退出替换模式
# 这种撤回动作的本身,不算“一次操作”
u # 撤回一次操作(一次操作通常指进入插入模式后退出前的所有操作、正常模式的一次粘贴/删除操作等),可以无穷次执行撤回
# 这种撤回动作的本身,算是一次操作
U # 撤回最新修改的那一行的所有操作,再次键入则重现这行的所有修改,再次键入,又会撤回该行的所有修改
# 其行为可以这样理解:
# 执行一行的修改时,会有一个寄存器记录了最新修改行的所有修改操作(多次进入插入模式再退出也没有关系,都算是对这行的最新修改),键入U时会按这个寄存器里的修改记录把修改内容撤回(也可按照这个寄存器里的修改操作重新恢复修改的内容)。但特点是你修改了行A,如果再修改行B,再修改回行A时,则之前对行A的修改会因为修改了行B而被打断(寄存器写入了行B的修改操作,把原先行A的修改操作覆盖掉,而再次修改行A,又等于用行A的最新修改覆盖掉了行B的修改记录),因此此时U撤回的是从B行修改完开始对行A的所有修改。(即只要换了行且执行了修改,那之前行的修改数据就不在这个行操作的寄存器里了,就无法使用这个U方式来撤回,只能用u来撤回。)
关于 U 撤回了该行最新修改,再次 U 会恢复修改内容,实际上是因为 U 属于一次修改操作,所以第一次 U 相当于一次“撤回之前修改”的操作,所以再次 U,就是撤回上一次 U 这个修改操作。
ctrl + r
ZZ # (大写Z)保存并退出
ctrl+z # 挂起 vim 临时回到 shell,在 shell 中键入 fg 返回vim
进入插入模式
i 从光标当前位置进入
a 从光标之后的位置进入
s 删除当前光标所在字符并从光标处进入
gh 即将替换光标所在字符并从光标处进入
I 从光标所在行首进入
A 从光标所在行尾进入
o 在光标所在行下方插入一行并从新行行首进入
O 在光标所在行上方插入一行并从新行行首进入
临时重复插入
正常模式中键入(<Esc>是退出插入模式回到正常模式,需要回到正常模式才能生效):
3akd<Esc> 在光标后插入kdkdkd(3次kd)
3iabc<Esc> 在光标所在位置插入abcabcabc(3次abc)
进入命令模式
:
# 仅在当前打开的vim中生效,退出当前vim(即便保存文件)后再打开vim,set设置会失效,想要一直生效需要去改配置文件。
:set nu 显示行号
:set nonu 不显示行号【默认】
:set hlsearch 高亮显示搜索到的关键词【默认】
:set nohlsearch 不高亮显示搜索到的关键词
:set ignorecase 忽略大小写的查找
:set noignorecase 不忽略大小写的查找【默认】
:nohlsearch 暂时关闭当前的搜索结果高亮,但如果再次 n 或 N 或重新查找别的关键词,都会恢复高亮
:set wrapscan 搜索到文件尾部时返回头部、搜索到文件头部时返回尾部继续搜索【默认】
:set nowrapscan 搜索到文件两端时,不循环到另一端继续搜索,而是停止搜索
:set incsearch 逐步搜索,对当前键入字符进行搜索而不必等待键入完成
:set noincsearch 关闭逐步搜索,需要等键入字符结束才开始进行搜索【默认】
# 持久生效方式:
vim /etc/vimrc
移动到文档最后一行,输入命令,如:
set nu
则以后打开vim(无论哪个文件)都会默认显示行号。
注意,如果在文件最后一行写入的是:
set nu
set nonu
两条相反的操作命令,因为文件会执行完最后一条命令,所以打开vim时默认不显示行号。
# /etc/vimrc 是对所有用户生效
# ~ 下的vimrc 仅对当前用户生效
如果没有 /etc/vimrc ,可能是安装系统的时候选择了最小安装等操作导致没有安装一些东西,vimrc 是一个叫做 vim-common 的软件包安装的文件,可以:
yum install vim-common
:w 保存到当前文件
:w /root/123.txt 另存为 /root/123.txt
此操作并不会把修改内容保存到当前文件,继续修改,不加文件名再次保存:w,也不会保存到之前另存为的文件(/root/123.txt)中,而是会保存到当前文件
如要另存为的 /root/123.txt 已经存在,需要加感叹号来强制覆盖保存:
:w! /root/123.txt
注意感叹号是紧跟在w后(没空格),而不是文件名后,否则就会保存到 /root 下的一个“123.txt!”的文件中
:q 文档没被修改时正常退出
:q! 不保存强制退出
:e! 强制返回到上次保存的状态(并非真正退出再重新打开,也相当于一次操作,可以用 u 撤回操作)
:suspend 临时回到 shell,挂起 vim,在 shell 中键入 fg 可返回 vim。
# 只是执行命令
:!命令
:! ifconfig
:!ifconfig # !后有没有空格都可以
# 执行命令并把输出结果粘贴回 vim
:r !命令
:r !ifconfig
:r!ifconfig
:r ! ifconfig # 中间有没有空格效果都一样
# 注意
命令中如果需要转义感叹号,需要用转义符号\
如:删除 "123.txt!"这个文件
:! rm 123.txt\!
:! rm 123.txt! # 这样删除的是 "123.txt" 而非 "123.txt!"
:12 # 光标移动到第 12 行行首的非空字符
:1,3y # 复制[1,3]行内容
:10,$y # 复制第10行及以后所有行
:1,$y # 复制所有行
:1,3d # 剪切[1,3]行内容
:10,$d # 剪切第10行及以后所有行
:1,$d # 剪切所有行
:2,3 co . # 将[2,3]行复制插入到光标所在行的下方
:2,3 co 5 # 将[2,3]行复制插入到第5行的下方
:3 co $ # 将第3行复制插入到文档末尾
:2,3 co $ # 将[2,3]行复制插入到文档末尾
:1,$ co $ # 将整个文档复制一份插入到文档末尾
:2,3 m . # 将[2,3]行剪切插入到光标所在行的下方
:2,3 m 5 # 将[2,3]行剪切插入到第5行的下方
:3 m $ # 将第3行剪切插入到文档末尾
:2,3 m $ # 将[2,3]行剪切插入到文档末尾
:1,$ m $ # 将整个文档剪切插入到文档末尾
/关键词 或 ?关键词
/a # 会标出所有的a(默认设置了高亮标出搜索到的关键词),并且光标移动到之前所在处起向后的第一个a
查 N 光标向前移动到关键词的上一个出现位置
?a # 会标出所有的a(默认设置了高亮标出搜索到的关键词),并且光标移动到之前所在处起向前的第一个a
查出来后,按 n 光标向前移动到关键词的上一个出现位置
按 N 光标向后移动到关键词的下一个出现位置
如果某个要查找的关键词比较长,不太方便输入,可以把光标先定位到该单词内部,按*或#键即可以该单词进行搜索:
'*' 相当于 / 搜索,n 往下,N 往上
'#' 相当于 ? 搜索,n 往上,N 往下
# 特殊
^ 表示行首插入(并非在行首非空字符前,而就是行首)
$ 表示行尾插入
如:
:20,24s/^/ /g #(/g可省略,只是更直观看到有多少个空格,此处是在20~24行行首插入4个空格,用于缩进)
# 行内
:s/关键词/替换词 # 在光标所在行搜索,并替换该行第一个关键词
:s/关键词/替换词/g # 在光标所在行搜索,并替换改行所有关键词
# 多行
:2,4s/关键词/替换词 # 替换[2,4]行每行的第一个关键词
:2,4s/关键词/替换词/g # 替换[2,4]行的所有关键词
:.,.+2s/关键词/替换词 # 替换光标所在行以及向下两行每行的第一个关键词(共3行)
:.,.+2s/关键词/替换词/g # 替换光标所在行及向下两行的所有关键词(共3行)
:.,.-2s/关键词/替换词 # 替换光标所在行以及向上两行每行的第一个关键词(共3行)
:.,.-2s/关键词/替换词/g # 替换光标所在行以及向上两行的所有关键词(共3行)
:.,$s/关键词/替换词 # 替换光标所在行(含)到最后一行(含)的每行第一个关键词
:.,$s/关键词/替换词/g # 替换光标所在行(含)到最后一行(含)的所有关键词
:1,.s/关键词/替换词 # 替换第一行(含)到光标所在行(含)的每一行第一个关键词
:1,.s/关键词/替换词/g # 替换第一行(含)到光标所在行(含)的所有关键词
:8,$s/关键词/替换词 # 替换第8行(含)到最后一行(含)每行的第一个关键词
:8,$s/关键词/替换词/g # 替换第8行(含)到最后一行(含)所有关键词
# 所有行
:%s/关键词/替换词 # 替换所有行的第一个关键词
:%s/关键词/替换词/g # 替换所有行的所有关键词
:1,$s/关键词/替换词 # 替换所有行的第一个关键词
:1,$s/关键词/替换词/g # 替换所有行的所有关键词
:g/关键词/s//替换词 # 替换所有行的第一个关键词
:g/关键词/s//替换词/g # 替换所有行的所有关键词
# 注意
# 如果替换对象本身是“/”,则可以使用其他符号来作为分隔(只需要保证分隔号一致不混用多种分隔号即可)
:%s,/,//,g
:%s!/!//!g
:%s#/#//#g
:%s@/@//@g
:%s:/://:g
# 除了在正常模式使用dd剪切再粘贴来移动行外,还可以:
:m+1 # 将光标所在行向下移动一行
:m-2 # 将光标所在行向上移动一行
# 注意向上移动 n 行,就要 :m-(n+1)
注意:单个文件保存后,不切换文件,是可以用 u 来撤回操作的(即使已经保存),但保存后切换文件,再切回来,是无法再使用u来进行撤回操作的。
vim file1 file2
此种方式,用
:args
查看打开的文件列表时,会显示vim打开的所有文件(不含后面用open打开的),当前文件会用中括号在列表中括出。
若事先没有打开文件,可以用 vim 同时打开两个文件:
vim file1 file2
,
此时支持:prev
与:next
来前后切换文件(不循环)。
也支持更方便的切换文件方式::bn
向后(可循环)与:bp
向前(可循环)。
vim 123.txt 234.txt
在 123.txt 中 yy 复制一行,
:next
进入到 234.txt
p 粘贴
:prev
返回到 123.txt
如果一开始已经打开了123.txt,要把内容复制到到没有打开的234.txt
经过实际尝试,不能只用vim命令模式临时用shell的vim命令打开234.txt(:! vim 234.txt),这会造成123.txt中复制内容只能粘贴到123.txt中,234.txt复制内容只能粘贴到234.txt中(即123.txt与234.txt如果是分别用shell的vim命令打开的话,不共享粘贴板)
如果坚持用shell的vim命令,需要用vim命令模式打开123.txt与234.txt
:! vim 123.txt 234.txt
然后再进行复制粘贴(但其实会频繁询问是否覆盖123.txt,不太好用,还不如直接退出123.txt重新同时打开vim 123.txt 234.txt)
已经打开123.txt,正确的复制方式应该是使用open命令。
:open file2
注意,多次用open方式打开其他文件后,实际上无论在哪个文件中使用
:args
查看打开文件的列表,都只会显示第一个(原先)打开着的文件名。而在初始文件或用open打开的任一个文件中使用:q
都会关闭所有文件。
若事先已经用vim打开了其中一个文件,则在其中利用命令模式使用open打开另一个文件:
:open file2
,(注意区别,open后只能跟一个文件,但vim可以跟多个,且vim前需要感叹号)
此时不支持:prev
与:next
切换文件,但支持更方便的切换文件方式::bn
向后(可循环)与:bp
向前(可循环)。
并且,此时两个文件的剪贴板是共用的。只需在修改文件后保存,即可切换文件。
split file2
与 open
类似的,还有 split
。
open
是同一个窗口中打开,split
是分开窗口打开。
split
的多个窗口之间切换方式:
# 先按ctrl+w,然后松手,单独按下一个键
# 如果存在某些热键冲突,ctrl+w 可以用 ctrl+shift+w 替代
ctrl+w+w # 依次切换窗口,可循环
# 垂直分割的屏幕
ctrl+w+h # 向左切换,不循环
ctrl+w+l # 向右切换,不循环
# 水平分割屏幕
ctrl+w+j # 向下切换,不循环
ctrl+w+k # 向上切换,不循环
open | split | |
---|---|---|
同 | - :args 显示的都是之前vim 打开的文件列表,而非后面用open 或split 打开的文件;- 都不支持 :prev 与:next ,都支持:bn 与:bp | |
异 | - :q 退出1个open的文件,该原始文件以及在该原始文件上open的所有文件都会退出- 无法用 :close 退出 | - 由于分开了窗口:q 哪个文件就仅仅退出哪个文件,即便退出了原始的文件,也不影响在在其上split的文件(退出了原始文件后,在split的文件中:args 还是显示原始的文件名)- 只要不是只剩一个文件,都可以用 :close 退出 |
split/new 分割窗口
:split
(:sp
) 或:vsplit
(:vs
)后若不跟文件名,则是将原来的文件另外打开一份(两份的修改是同步的),使用场景是两个屏幕分别显示文件的不同位置部分内容。
但 new、vnew 后不跟文件名,则是新建一个未命名文件。
:split file2 或 :new file2 # 水平分割
:sp file2 # 水平分割
:vsplit file2 或 :vnew file2 # 垂直分割
:vs file2 # 垂直分割
假设 vim 打开的是 file1 file2,后续用在file1中 open 打开了 file3、file5,在 file2 中用 open 打开了 file4。
vim | file1 | file2 |
---|---|---|
open | file3 | file4 |
open | file5 |
则
:args
显示的会是:file1、file2。:bn
、:bp
可以在所有文件中切换(file1~file5):prev
、:next
只能在 file1、file2中切换(即便目前在file3,:next 也会是 file2,而非 file4 或 file5)进入可视模式
v # 小写v,visual 字符可视模式:移动光标以字符为单位进行选择
V # 大写V,visual line 行可视模式:移动光标以行为单位进行选中
ctrl+v # visual block 块可视模式:移动光标会以上下左右对齐的矩形块为单位来进行选中
d # 选中块后,按 d 键就可以剪切块;
# 选中行后,按 d 键就可以剪切行;
# 选中字符后,按 d 键就可以剪切所选的所有字符;
y # 选中块后,按 y 键就可以复制块;
# 选中行后,按 y 键就可以复制行;
# 选中字符后,按 y 键就可以复制所选的所有字符;
p # 复制块后,按 p 键就可以在光标后粘贴块(光标所在行为块的第一行,块的其他行在其下仍旧按方块格式插入到原本光标所在行下方行的各行内);
# 复制行后,按 p 键就可以在光标所在行下方粘贴行;
# 复制字符后,按 p 键就可以在所在光标后粘贴所选的所有字符;
x # 选中块后,按 x 键就可以删除块;
# 选中行后,按 x 键就可以删除行;
# 选中字符后,按 x 键就可以删除所选的所有字符;
I # 大写i,光标跳转到选中块的右上方
输入要插入的字符,如:abc
按 Esc 2次退出,
此时,选中块的每行的块前面都会被插入abc
如:
12345
12345
12345
选中块为 1~2行的345,键入I后,插入abc后变为:
12abc345
12abc345
12345
另外其实可以在键入I后移动光标到指定位置(但需要仍在选中块所在的第一行,且光标不移动到块的左边,即允许在块内以及块的右边)来实现这种重复批量插入操作。
# 注意:
如果键入I后光标移动到选中块左方(仍在块所在第一行),此时键入内容,则无论是在块所在第一行左边的什么位置插入的n个字符(与块距离远近无关),块除了第一行外的其他行,都会在块前方插入块所在第一行块前面的n个字符(按插入后为标准)。
如:
defgabcde
abc123
123
123
选中2~4行的12,光标移动到第二行行首键入5个d:
defgabcde
dddddabc123
123
123
按 2 次 Esc 退出后,变为:
defgabcde
dddddabc123
ddabc123
ddabc123 # 因为第2行的“12”前的5个字符是“ddabc”
如果选中2~4行的12,光标移动到第二行如下键入:
defgabcde
NUMaDEb c123
123
123
按 2 次 Esc 退出后,变为:
defgabcde
NUMaDEb c123
aDEb c123
aDeb c123 # 因为第2行的“12”前的6个字符是“aDEb c”