0%

学习 vi 和 vim 编辑器(1):基础操作

对于程序员而言,一个舒适、顺手、功能强大的开发环境必不可少,而编辑器又是其中的重中之重。虽然现在有很多功能强大的 IDE,但是在 Linux 开发环境中,Vim 编辑器有其独特的优势,它可以让我在服务器环境中直接修改代码,加快 编码-编译-调试 周期。而且 Vim 被誉为编辑器之神,是有追求的 geeker 必备技能之一。

本系列文章是对《学习vi和Vim编辑器》一书的总结,也是我的 Vim 入门之旅。

vi 基础

Unix 系统中有很多编辑器,可以分为两种类型:

  • 行编辑器:每次只能在屏幕中显示文件的一行,如 ed 和 ex 编辑器
  • 全屏编辑器:可以在屏幕上显示文件的一部分,如 vi 编辑器

vi(读为 vee-eye )编辑器是 UNIX like 操作系统的标准文本编辑器。vi 是 visual editor 的缩写,其主要有两种模式:

  • 命令模式:所输入的一切都会被解释为命令
  • 插入模式:所输入的一切都会被当做输入的文本插入到正在编辑的文件中

在 vi 编辑器中,命令有如下特点:

  • 命令是大小写敏感的
  • 输入命令时,命令不会显示在屏幕上
  • 输入完命令后不需要再按 enter 健

但是也有一组命令会显示在屏幕的底端,这些命令之前有特殊的符号,例如冒号用于开始所有的 ex 命令。vi 编辑器使用的底层编辑器就是 ex 行编辑器,vi 只是其可视化的模式。因此可以在 vi编辑器中直接使用 ex 编辑器的命令。

文件操作

可以使用 vi 编辑器来编辑任何文本,需要说明的是,vi 把需要编辑的文本复制到内存中的缓冲区中,因此我们修改的只是内存中文件的副本,只有对缓冲区里的内容进行保存,才能将编辑结果更新到磁盘的文件中。

打开文件

1
vi [filename]

如果 filename 当前已经存在,则编辑对应的文件;如果 filename 不存在,那么 vi 将打开一个未命名的缓冲区,当需要保存该未命名缓冲区的内容时,仍需要指定 filename(即新建了一个名为 filename 的文件)。

保存与离开

ZZ 保存编辑结果,离开vi编辑器

还可以使用 ex 命令来保存编辑结果:

  • :w 只保存编辑结果,不离开编辑器
  • :wq 保存编辑结果并离开 vi 编辑器(等效于 ZZ)

结束但不保存编辑结果:

  • :e! 该命令可以消除当前的所有编辑结果,直接回到最后一次存储时的文件内容
  • :q! 也是直接忽略当前的编辑结果,直接回到最后一次存储时的文件内容,同时离开vi编辑器

为什么这两个命令后面都有感叹号呢,因为 :e 和 :q 命令都会让当前的编辑效果消失,而 vi 编辑器一般不会让你放弃编辑结果。因此加上感叹后,就可以使 vi 不理会这个禁令。

一些小技巧

  • 高高兴兴编辑了半天,最后发现没有写权限:可以使用 :w filename 将当前结果保存到一个新的文件
  • 尝试写文件,却发现文件系统已满:解决方法有很多,一种方法是:可以将该文件写入到具有剩余空间的文件系统。或者可以直接输入:!sh 回到 shell 环境中,然后删除当前文件系统的一些大文件。(在 ex 命令中可以在感叹号后面接 UNIX 命令,直接执行相应的 UNIX 命令)。

移动光标

当需要编辑文本时,首先需要做的可能就是将光标移动到需要编辑的地方。在命令模式中,移动光标有如下命令:

  • h:向左移动一个字符
  • j:向下移动一行
  • k:向上移动一行
  • l:向右移动一个字符
  • w:将光标移动到下一个单词(其中符号和标点被认为是一个单词)
  • W:将光标移动到下一个单词(其中标点和符号不被当成一个单词)
  • b:将光标倒退一个单词(其中标点和符号被当成一个单词)
  • B:将光标倒退一个单词(其中标点和符号不被当成一个单词)
  • e:移动到单词结尾(移动到单词本身结尾)
  • E:移动到单词结尾(移动到该单词的标点符号之后)

可以在这些移动命令前加上数字,达到命令重复的功能。例如输入4l 即相当于按下了 4 次l命令。这种命令重复功能可以给我们更多选择,并增强命令的功能,应该牢记。

在一行中快速移动的命令有两个:

  • 0:移动到行的开头
  • $:移动到行的尾部

可以使用G命令直接移动到指定行。直接输入G命令,是移动到文件的尾部, nG则是移动到文件的第 n行,gg 命令移动到文件起始位置。

默认 vi 不显示文件的行号,可以通过 :set nu 选项来显示文件的行号。另外,通过执行 CTRL+G 命令,可以在屏幕底端显示一些行信息,包括当前的行号、文件的总行数、当前位置占全文的百分比。

简单编辑

插入文本

以下编辑命令都会使 vi 编辑器从命令模式转化为插入模式,之后输入的一切都会被当成输入文本更新到缓冲区中

  • i:插入文本,输入i命令时,光标不移动,在光标之前的位置开始插入文本
  • a:添加文本,输入a命令时,光标会向后移动一个字符,因此是在原先光标之后输入文本,即添加本文
  • A:在一行的结尾处添加文本
  • I:在一行的开头处添加文本
  • o:在光标所在位置的下一行添加新的一行
  • O:在光标所在位置的上一行添加新的一行

以上插入命令中,都可以接受数值参数。例如50i就可以直接插入50个字符,10a*-就可以直接添加10个*-字符对。

替换文本

c 命令可以替换文本。替换命令可以认为是先删除需要被替换的文本,然后等待输入新的文本,输入的文本没有长度限制。使用c命令时,为了指定有多少文本需要更改,可以把c命令与光标移动命令结合使用,例如:

  • cw:替换从光标所在位置到该单词的结尾
  • c$:替换从光标所在位置到该行结尾,也可以直接使用 C 命令
  • c0:替换 从光标所在位置到该行开头
  • c2b:替换从光标位置到往回两个单词
  • cc:替换一整行,此时无论光标在该行何处,cc 命令都直接将一整行文本替换成输入的新文本

其实不止c命令,其它如d(删除),y(拖拽)等命令,都有如下的一般形式:(command)(TextObject)形式。这里的 command 就是我们的c、d、y 等编辑命令,而 TextObject 则是光标移动命令,指明 command影响的文本范围。

其它替换命令有:

  • s:用于字符的替换,它首先删除需要被替换的字符,然后等待插入新的字符
  • S:命令直接替换一整行文本,等同于cc命令,但和C命令有区别
  • r:命令也可以把一个字符替换为另一个字符,但是替换之后直接回到命令模式
  • R:命令也用于字符的替换,相比于r一次只能替换一个字符,按下R键后,则会进入覆盖模式:即你输入的字符将逐一覆盖原有的字符,直到按下 ESC 键为止。R命令最多只能覆盖一整行
  • ~: 命令用于对当前字符进行大小写转换,转换之后光标自动移到下一个字符

删除文本

vi 中,删除命令为 d,其也具有 (command)(TextObject) 的使用形式。只要理解了这一点,接下来的删除命令组合就不需要死记了:

  • dw:删除光标所在位置到该单词的结尾,该命令会将这个单词之后的空白也删除
  • dE:类似于dw命令,但是不会删除单词之后的空白
  • de:dw 和 dE 命令都会把紧跟在单词之后的标点删除,但是de命令只删除单词本身,不删除标点符号
  • d$:删除光标所在位置到该行结尾处,和D命令效果一样
  • d0:删除光标所在位置到该行开始处
  • dd:无论当前光标处于该行的哪个位置,都直接删除一整行

如果需要删除字符,有更简单的命令,当然这些命令也可以加上数值参数:

  • x:删除光标所在的字符;
  • X: 删除光标之前的一个字符;

移动文本

vi 编辑器中移动文本是通过删除文本后再放置实现的:每次需要移动文本块时,先删除该文本块,这样该文本块的内容就会存储在特殊的缓冲区中,然后将光标移动到正确的位置,使用放置命令把刚刚删除的文本放在新的位置,从而实现文本的移动。

  • p:将缓冲区的文本放在光标之后,如果移动了一行及一行以上的文本,则是放置在光标之后的新的一行,如果移动了不到一行,则将移动的文本放置在光标之后的同一行
  • P:与p命令类似,只不过是将缓冲区中的文本放置到光标之前

需要说明的是,p命令是将刚刚删除的文本放置到指定的位置,所以一定要在做下一个删除动作前,将当前删除的本文恢复过来,否则如果做了一个影响缓冲区的编辑动作(删除,拖曳等),那么当前被删除的文本就会消失。关于这一点,后续文章会详细讲解。

所以,通过 xp 命令可以快速完成两个字母的对调。

复制文本

复制文本通过两个命令: y(拖曳)和p(放置)来实现。y 命令也具有(command)(TextObject)的使用形式,因此可以将拖曳命令和光标移动命令进行组合使用,从而指定需要拖曳的文本范围。Y命令等同于yy命令,都表示拖曳一整行。

拖曳命令和删除命令共用一个缓冲区,所以每一个新的删除或拖曳命令都会覆盖缓冲区中的内容。

其它命令

  • . :重复命令,重复上一次修改
  • u:撤销命令,撤销上一次修改
  • U:撤销当前所有对某一行的编辑动作,但是需要光标还在这一行,一旦光标离开了这一行,就无法使用U命令对原先的这一行进行恢复了
  • J:合并两行,如果在J命令前加上数值参数,则可以指定需要合并的行数