Linux深入探索03-文本编辑vi/vim
----- 最近更新【2022-01-25】-----
本文目录结构预览:
- 一、简介
- 二、存储原理
- 三、使用 vim
1、语法
2、vim的模式 - 四、命令模式
1、移动光标
2、搜索
3、使用行号
4、替换文本
5、删除与撤销
6、复制与粘贴
7、换行
8、设置选项
9、使用shell命令
10、插入文件中的数据
11、保存与退出 - 五、异常恢复
- 六、初始化文件
- 七、总结
- 八、参考
一、简介
Unix系统的文本编辑器有许多种(vi、vim、nano、emacs等),但本文只讨论vi/vim,因为vi/vim是Unix系统上最常用的文本编辑器。绝大部分Unix系统都默认安装有vi或者vim程序,或者二者同时安装。
其实vim就是vi的改进版,而且现在很多Linux系统都用vim取代了vi,但是同时又保留了vi这个命令的使用习惯。意思就是,在你的系统上vi和vim命令都可以使用,但其实你使用的是同一个程序,因为vi指向的也是vim。
用下面的方法你可以证明你使用的vi是不是vim:
linux1@noseeu:~$ which vi
/usr/bin/vi
linux1@noseeu:~$ which vim
/usr/bin/vim
linux1@noseeu:~$ ls -l /usr/bin/vi*
lrwxrwxrwx 1 root root 20 Feb 1 2021 /usr/bin/vi -> /etc/alternatives/vi
lrwxrwxrwx 1 root root 21 Feb 1 2021 /usr/bin/vim -> /etc/alternatives/vim
-rwxr-xr-x 1 root root 3165768 Nov 8 14:21 /usr/bin/vim.basic
linux1@noseeu:~$ ls -l /etc/alternatives/vi*
lrwxrwxrwx 1 root root 18 Feb 1 2021 /etc/alternatives/vi -> /usr/bin/vim.basic
lrwxrwxrwx 1 root root 18 Feb 1 2021 /etc/alternatives/vim -> /usr/bin/vim.basic
linux1@noseeu:~$
或者你直接在命令行输入vi也可以知道。
这两者的使用方法其实基本是一样的,本文将以vim为环境展开介绍。
二、存储原理
当使用vim时,存放数据的存储区域称为编辑缓冲区(editing buffer)。当使用vim编辑文件时,vim就将文件的内容复制到编辑缓冲区,因此你处理的内容其实是数据的副本,而不是原始数据。
vim通过将编辑缓冲区保存在一个交换文件(swap file)中,提供了出色的恢复功能,交换文件与正在编辑的文件存储在同一个目录中。交换文件的名称一般是.原文件名.swp
这样的格式。
三、使用 vim
1、语法
vim - Vi IMproved, a programmer's text editor.
vim [options] [file ..]
vim [options] -
vim [options] -t tag
vim [options] -q [errorfile]
vim 命令的选项非常多,但是大多时候我们并不需要用到,我们最常用的只是“vim [文件名]
”。
一般情况下,我们还需要知道的是这两个选项:-r
(恢复文件)和 -R
(只读模式),后面会详细介绍。
对于习惯使用 vi 的同学,可以使用vim -C
来启动 vim,这个选项可以使 vim 尽可能地像 vi 一样。
2、vim的模式
vim有两种模式:命令模式(command mode)和输入模式(input mode)。
1)在命令模式时,所有键入的键都会被解释成命令。
当启动vim时,你所处在的模式就是命令模式。
可以使用这些命令切换到输入模式:i、a、I、A、o、O。当然,这6种并不是所有切换到输入模式的方式,它们是比较常用的方式。
命令 | 说明 |
---|---|
i (insert) | 切换到输入模式:在当前光标位置前插入数据 |
a (append) | 切换到输入模式:在当前光标位置后插入数据 |
I | 切换到输入模式:在当前行开头处插入数据 |
A | 切换到输入模式:在当前行末尾处插入数据 |
o (open) | 切换到输入模式:在当前行下面插入一行 |
O | 切换到输入模式:在当前行上面插入一行 |
2)在输入模式时,键入的内容将直接插入到编辑缓冲区。
在输入模式时按
当你处于输入模式时,Vim将在屏幕下方显示如下提醒:
-- INSERT --
下面将着重介绍命令模式下的常用操作。
四、命令模式
1、移动光标
按键 | 说明 |
---|---|
← / |
将光标向左移动一个位置 |
→ / |
将光标向右移动一个位置 |
↑ | 将光标向上移动一个位置 |
↓ | 将光标向下移动一个位置 |
将光标移动到下一行的开头 | |
0(数字0) / |
将光标移动到当前行的开头 |
$ / |
将光标移动到当前行的末尾 |
^ | 将光标移动到当前行第一个非空字符上 |
w | 将光标移动到下一个单词的词首 |
e | 将光标移动到下一个单词的词尾 |
b | 将光标移动到上一个单词的词首 |
) | 向前移动到下一个句子 |
( | 向前移动到上一个句子 |
} | 向前移动到下一个段落 |
{ | 向前移动到下一个段落 |
H | 将光标移动到屏幕的顶部(high) |
M | 将光标移动到屏幕的中间(middle) |
L | 将光标移动到屏幕的底部(low) |
向下(前)移动一屏 | |
向上(后)移动一屏 | |
`` | 将光标返回上一个位置 |
为了增强移动命令的功能,可以通过在命令前面输入一个数字来重复执行光标移动命令。如:向下移动10行“10↓
”,或者向前移动5个单词“5w”。通常对于任何vim命令使用重复数次都是允许的,只要这样做有意义。
2、搜索
命令 | 说明 |
---|---|
/ | 向下搜索一个匹配值 |
? | 向上搜索一个匹配值 |
如你要搜索单词was,则可键入“/was
”,然后按
键。系统就会从你光标的位置开始向下搜索,然后跳到第一个搜索到的位置。
你需要继续搜索的话,则可以按n
键,将延相同方向继续搜索(/
模式继续向下搜索,?
模式继续向上搜索),按N
键则延相反方向搜索。
为了更加的灵活,vim允许使用正则表达式指定搜索内容。如:输入/R[a-z]*d
然后回车。
3、使用行号
显示行号::set number
隐藏行号::set nonumber
跳到指定行号,如跳转到第50行:50G
,注意G是大写。
跳到文本的第一行:gg
,连续按两次g键,相当于1G
。
跳到文本的最后一行:G
,大写G。
也可以通过键入:
后面跟行号,再按回车跳转到指定行。
如跳到200行::200
跳到文本末尾::$
,等同于G
4、替换文本
命令 | 说明 |
---|---|
r |
可以将一个字符替换为另一个字符 |
:s/pattern/replace/ |
替换当前行 |
:lines/pattern/replace/ |
替换指定行,line 表示行号 |
:line,lines/pattern/replace/ |
替换指定范围的行 |
:%s/pattern/replace/ |
替换所有行 |
~ |
使用~ 键,可以使用当前光标处的字符进行大小写切换 |
pattern 是希望被替换掉的模式,replace 是替换文本。 |
在命令行的末尾,可以使用c
告诉vim在替换前需要再次确认,而使用g
则表示替换该行的所有匹配项。
当进行多条替换并未结束的时候,可以通过按
来中途停止,这将放弃整条命令的替换。
如:
:%s/UNIX/Linux/g
表示把全文的UNIX替换为Linux。
:.,$s/UNIX/Linux/g
表示从当前行到最后一行的UNIX替换为Linux,.(点号)代表当前行,$代表最后一行。
5、删除与撤销
删除:
命令 | 说明 |
---|---|
x | 删除当前光标处的字符 |
X | 删除光标左边的字符 |
D | 删除从当前光标到本行末尾的字符 |
dd | 删除当前行(dd前面也可以加数字,如10dd 从当前行开始往下删除共10行) |
:lined |
删除当前行,line 表示行数,如::5d 删除第5行,:%d 删除全部 |
:line,lined |
删除指定范围的行,如:1,.d 将第一行到当前行之间的所有行删除,:1,$d 删除全部 |
d后面还可以跟一条光标移动命令,这时将删除从当前光标位置到光标移动命令所指示位置的所有字符。
如:
dw
,删除一个单词
d10w
,删除10个单词
db
,向后删除一个单词
d2)
,删除2个句子
dgg
,删除当前行到第一行的所有内容
撤销:
命令 | 说明 |
---|---|
u | 撤销上一命令的修改内容 |
U | 恢复当前行 |
. | 重复上一命令的修改 |
U
命令可以将撤销自移动到当前行的那一刻起,对当前行所进行的所有改变。U
命令可以撤销大量改变,一次就将当前行的所有改变都恢复。但是,仅当没有离开这一行时U
命令才有效。
使用.
命令的时候要特别小心。当你使用u
命令撤销一个修改时,点击一次.
将取消你刚刚的撤销。
.
命令的详细介绍是:重复上一命令对编辑缓冲区的修改。
比如:你在文本某个位置插入了一个单词(添加了一个单词),然后你不想要这个单词了,你可以按u
撤销刚刚插入的单词(单词被删了)。但突然你又想要了,你就可以按.
来取消刚刚的撤回(单词又回来了)。但这时你再按一次.
的话,那刚刚恢复的单词会再恢复一次(这一般不是你要的结果)。
再比如:当你用dd
删除一行文本后,按.
你会发现也会继续再删除一行文本,这时你继续按.
它还会继续删。
6、复制与粘贴
vim总是在一个称为无名缓冲区(unnamed buffer)的储存区中为上一次删除(或者复制)保存一份副本。在任何时候,都可以使用p和P(put 放入)命令将无名缓冲区的内容复制到编辑缓冲区中。注意,无名缓冲区每次只能存放一次内容,也就是最新的一次。
p(小写)命令将无名缓冲区的内容插入到光标当前位置之后。如果无名缓冲区的内容是整行的话,那么p命令会将无名缓冲区中的行插入到当前行的下面。
P(大写)命令将无名缓冲区的内容插入到光标当前位置的左边。如果无名缓冲区的内容是整行的话,那么p命令会将无名缓冲区中的行插入到当前行的上面。
删除命令前面已经介绍过了,那么怎么把内容复制到无名缓冲区呢?
在不删除文本的情况下,可以使用y、yy和Y命令将文本复制到无名缓冲区中,我们称这是接出(yank)了文本。
常用操作组合:
命令 | 说明 |
---|---|
p | 把无名缓冲区的内容,插入到光标后面/下面 |
P | 把无名缓冲区的内容,插入到光标前面/上面 |
xp | 调换两个字符的位置 |
deep | 调换两个单词的位置 |
ddp | 调换两个行的位置 |
yw | 接出(复制)1个单词 |
y10W | 接出(复制)10个单词(忽略标点符号) |
yy | 接出(复制)1整行 |
10yy | 接出(复制)10整行 |
Y | 可以用Y(大写)来代替yy |
除了上面常用的复制粘贴命令,当我们遇到大量的行需要进行复制粘贴时,可以使用下面的方法:
:co
(copy,复制)与:m
(move,移动)。其中:co
不删除原始行,:m
删除原始行。
命令 | 说明 |
---|---|
:x[,y]coz |
把x(或者x至y)行复制到z行的下面 |
:x[,y]mz |
把x(或者x至y)行移动到z行的下面 |
上面的x、y和z都表示行号。 |
7、换行
1)换行
命令 | 说明 |
---|---|
r | 可以将一个字符替换为另一个字符 |
所以当键入r 然后 回车,就变成换行了。 |
2)合并行
把光标移动到某一行,然后键入J
(大写字母“j”),这将会把当前行与下一行合并成一行。
J
的前面也可以加数字,如5J
合并5行(把当前行与它下面的4行合并)。
8、设置选项
前面的第3小节【3、使用行号】用的就是vim中设置选项的语法:set number
。
设置选项的命令语法有以下两种形式:
:set [no]option...
:set option[=value]...
:set option
表示打开某项设置,:set nooption
表示关闭某项设置,vim中很多设置选项默认值都为off(关闭状态)。
常用设置选项:
命令 | 缩写 | 默认值 | 说明 |
---|---|---|---|
:set number 、:set nonumber |
:set nu 、:set nonu |
off | 显示行号、(默认)隐藏行号 |
:set tabstop=num |
ts |
8 | 设置制表符的间距(默认一般为8) |
:set ignorecase |
ic |
off | 在搜索过程中忽略大小写(默认不忽略) |
:set list |
无 | off | 将制表符显示为^I,将行的结束显示为$ |
:set lines=num |
无 | 24 | 屏幕显示文本的行数(窗口/屏幕大小-1) |
:set shiftwidth=num |
sw |
8 | aotoindent(自动缩进)使用的空格数量 |
:set all |
查看所有选项的值(这个挺有用的) | ||
:set |
:set 命令本身可以查看那些改变了默认值的选项 |
||
:set option? |
在指定选项后面加? (问号)可以查看该选项的值,如::set number? |
||
:set wrapmargin=num |
wm |
0 | 该选项只影响输入模式,表示vim编辑时输入的行内容离右边缘num个字符数时自动换行,0表示不自动换行 |
设置选项的语法允许多个选项同时设置,如::set number tabstop=4
9、使用shell命令
在vim中有几种调用常规shell的方法。
命令 | 说明 |
---|---|
:!command |
:!command 表示:! +shell命令。暂停vim,执行shell命令 |
:!! |
暂停vim,执行上一条shell命令 |
:sh 、:!bash |
暂停vim,启动一个新shell |
:r!command 、:r !command |
在vim的编辑缓冲区插入shell命令的输出内容,r 后面可以加一个空格 |
如:
:!date
,将暂时退出vim执行date
命令,执行完date
命令后再按
按就可以回到vim了。
:r!date
,将在你的光标处的下一行插入date
命令的输出内容。
:sh
与:!bash
命令可以暂时退出vim回到shell界面,这时你可以在shell界面执行多条shell命令。执行结束之后可以按
或者加入exit
就可以回到vim。
与下面小节介绍的一样:r
可以加入行号。
10、插入文件中的数据
在vim中,想把现有的文本插入当前的编辑缓冲区,可以使用:r
命令,语法如下:
命令 | 说明 |
---|---|
:[line]r filename |
line 是行号,filename 是文件的名称 |
:r
命令读取文件filename
的内容,并将该内容插入到编辑缓冲区的指定行之后。如果末指定line
则表示插入到当前行之后。
如:
:0r test.txt
表示把test.txt文件的内容插入到编辑缓冲区的开头。
:$r test.txt
表示把test.txt文件的内容插入到编辑缓冲区的末尾。
11、保存与退出
命令 | 说明 |
---|---|
:w |
write,将数据写入到原始文件,即保存文件 |
:w filename |
将数据写入到一个新文件 |
:w! filename |
覆盖一个已有的文件 |
:w>>filename |
将数据追加到指定文件中 |
ZZ 、:wq |
即 ,保存文本并退出vim |
:!q |
强制退出,不保存修改 |
如果忘记了正在编辑哪个文件,可以按
在自用vim编辑文件的时,当你完成了当前文本的工作,使用以下命令可以不需要退出vim直接打开新的文件。
命令 | 说明 |
---|---|
:e filename |
切换到一个新文件 |
:e! |
重新打开原文件 |
使用该命令要确保当前文本已经用:w 命令保存了,否则vim会弹出一个错误提示。当然,不需要保存的话你也可以用:e! filename 命令强制切换。 |
当你对当前文件做了很多更改时,突然全都不想要了,那你可以用:e!
命令重新打开原始文件。
五、异常恢复
当你在使用vim编辑文件的时候,突然程序意外中断了(如断电、断网、程序崩溃、人为失误等),这时怎么办。
放心,vim也提供了非常出色的恢复功能。前面也有介绍,当你在使用vim编辑文件时,vim将文件的内容保存到一个编辑缓冲区中,就是一个交换文件(swap file),名称一般是.原文件名.swp
这样的格式。
当你正常保存退出vim后,这个交换文件会被自动退出。但是当你是意外中断编辑的时候,该文件不会被自己删除,这时你会可以用它来恢复你的数据了。
这里我可以模拟一下,在我编辑文件testmini时,由于断网意外与服务器连接突然中断了,我修改的内容也没保存。
这回我重新登录系统时,可以看到如下:
linux1@noseeu:~$ ll
-rw-rw-r-- 1 linux1 linux1 1162 Dec 22 18:07 testmini
-rw-r--r-- 1 linux1 linux1 12288 Dec 22 18:07 .testmini.swp
linux1@noseeu:~$
此时,文件夹中多了一个文件.testmini.swp,接下来我可以用如下方法进行恢复:
方法1:直接用vim打开原始文件,然后根据提示操作。
当我用vim testmini
直接打开时可以看到如上的提示。vim给我们提供了5个选项:
命令 | 说明 |
---|---|
[O]pen Read-Only | 以只读模式打开(打开的是编辑前的原文件) |
(E)dit anyway | 继续编辑(也是打开编辑前的原文件) |
(R)ecover | 恢复 (把异常中断的数据恢复,然后打开编辑) |
(Q)uit、 (A)bort | 退出(不进行任何操作) |
从上表可以看出,到这里我们按R
(这里不区分大小写)键然后回车,就可以恢复我们编辑的数据。(之后记得要保存再退出)
方法2:使用命令vim -r filename
linux1@noseeu:~$ vim -r testmini
这时提示如下:
这时直接按回车就行(然后保存、退出)。
最后!不管你是通过以上两种方法中的哪一种来恢复数据,还有最后一步就是你都得手动删除.原文件名.swp
这个文件。
linux1@noseeu:~$ rm .testmini.swp
否则你每次用vim打开这个文件的时候它都会弹出提示。
六、初始化文件
在vim启动时,它会在home目录中查找初始化文件。如果存在初始化文件,vim会读取并执行查找到的初始命令。
vim首先会查找.vimrc
(rc, run commands)文件,如果该文件不存在,那么继续查找.exrc
(ex, vi的早期版本)。如果两个文件都同时存在,vim只会读取.vimrc
文件。
其时,vim的初始化文件可以非常简单,一般就是经常使用的一些set命令。如下是我创建的一个.vimrc
文件:
七、总结
本文的内容包括了vim的绝大部分常用操作和命令,希望能够帮助到大家。
其实,这只是vim的冰山一角,vim的功能是如此的强大和复杂,以至于可以说“没有一个人能知道vim的所有内容”,事实上也没有这个必要。
如果觉得本文没有能满足你的胃口,想要去了解更多,那么你也可以去查看vim的其它相关教程。在linux系统可以直接使用命令vimtutor
查看《VIM Tutor》,打开看到的页面将会如下:
《VIM Tutor》总共分为七大课时,每个课时包含若干小节,然后每个课时最后都会附带一篇总结,也是一篇不错的教程。
最后,这里总结几个大家可能会感兴趣的vim的其他功能,方便大家想了解的时候可以去查找:
- 分屏操作 Split
- 折叠操作 Folding
- 语法高亮 Syntax Highlighting
- 视图模式 Visual mode
- 内置脚本 Vim script
- 宏 Macro
我试了一下分屏、折叠这两个功能,感觉还挺好玩的,哈哈哈......
分屏、折叠的效果图:
最后,最后
花了两天两夜的时间,终于把关于vim的知识点整理完了。有哪里写错的,或写得不好的地方,欢迎大家批评指正。
八、参考
VIM User Manual:https://vimhelp.org/usr_toc.txt.html (更全面!)
书箱:《Unix & Linux 大学教程》第二十二章 (美)Harley Hahn 著 张杰良 译
教程:《 VIM Tutor — Version 1.7》 Michael C. Pierce、Robert K. Ware