文本编辑器有很多,比如图形模式下的gedit、kwrite等,文本模式下的vi、vim(vi的增强版本)、emacs等,本文介绍vim的一些基本操作

# 模式

vim有3种模式

  • 普通模式
  • 编辑模式
  • 命令模式

# 普通模式

由Shell进入vi编辑器时,首先进入普通模式。在普通模式下,从键盘输入任何字符都被当作命令来解释。

如下是普通模式视图

vim普通模式

# 编辑模式

编辑模式主要用于文本的输入。在该模式下,用户输入的任何字符都被作为文件的内容保存起来,并在屏幕上显示出来。

在普通模式下,输入a(附加命令)、c(修改命令)、i(插入命令)、o(另起新行)、r(取代命令)以及s(替换命令)都将进入编辑模式,此时vi窗口的最后一行会显示“Insert”

vim编辑模式

# 命令模式

命令模式下,用户可以对文件进行一些附加处理。尽管普通模式下的命令可以完成很多功能,但要执行一些如字符串查找、替换、显示行号等操作还是必须要进入命令模式的。

# 模式切换

可以按照如下方式切换工作模式

vim工作模式切换

# vi启动与退出

通过直接输入vi进入vi的普通模式,可用参数如下

  • -R 只读模式
  • -x 对文件进行加密

在命令模式下输入:q退出

# 光标移动

# 向指定方向移动(前后左右)

普通模式下,使用组合键数字N(optional) + 方向键实现光标移动

方向键

  • 前 l、Space键或方向键→

  • 后 h、空格键或方向键←

  • 上 -、k、Ctrl+p或方向键↑

    • +和Enter键是将光标移到下一行的行首
    • 其余命令仅是移到下一行,所在的列不变。如果下一行比当前光标所在位置还短,则下标到行尾。
  • 下 +、Enter键、j、Ctrl+n或方向键↓

    • -命令将光标移到上一行行首
    • 另外3个保持在同一列。

# 移动到行首

普通模式下使用0或^命令

  • 0 将光标移到当前行的第一个字符
  • ^ 将光标移到当前行的第一个非空白符

# 移至行尾

普通模式下使用$命令

如果在该命令前加数字n,则光标将下移到n-1行的行尾。

# 按词移动

  • 按词前移 - 将光标后移至上一个单词的开头
    • w 以标点符号或空白符(如制表符、换行符或空格符)分隔的字母或数字串
    • W 搜索的词被定义为非空白符字符串
例如有字符串:

    echo l > /proc/sys/net/ipv4/conf/default/rp_filter

连续输入命令w,光标从行首移动的位置为:e、l、>、/、p、s、…、/、r、r。
而命令W,光标从行首移动的位置为:e、l、>、/、r。
1
2
3
4
5
6
  • 按词后移 - 将光标后移至上一个单词的开头

    b和B

  • 移至词尾

    e和E

# 移至指定行

  • 命令模式 :行号
  • 普通模式 行号G

显示行号

:set number
:set nu
1
2

去掉行号

:set nonumber
:set nonu
1
2

# 屏幕滚动

在文件的编辑查看过程中经常涉及屏幕的滚动问题。

在vi编辑器中,尽管可以使用键盘上的Page Up键和Page Dawn键来完成这些操作,甚至使用方向键↑和↓,但是效率比较低,下面来看看相关屏幕滚动的命令。

  1. 向后滚动一屏

    使用的命令为:Ctrl+f (滚屏后保留上一屏的最后两行)

  2. 向后滚动半屏

    使用的命令为:Ctrl+d

  3. 向前滚动一屏

    使用的命令为:Ctrl+b

  4. 向前滚动半屏

    使用的命令为:Ctrl+u

  5. 屏幕定位

    • 使用命令zz将当前行置为屏幕正中央
    • 使用命令zt会将当前行置为屏幕顶端
    • 命令zb则会将当前行置于屏幕底端
  6. 滚动至第一屏或最后一屏

    • gg 定位于文件第一屏
    • G 定位于文件最后一屏

# 文本输入、删除与修改

文本的输入、删除与修改是文件编辑的基本操作,其中大部分命令会将vi编辑器由普通模式切换为编辑模式,下面来介绍这些命令。

  1. 插入命令

    文本的插入命令为i和I。其中i是将其后输出的字符插入到当前光标位置之前。命令I是将其后输入的字符插入到当前光标所在行的行首。

  2. 附加命令

    附加文本的命令为a和A,其中命令a是将其后输入的字符插入到当前光标位置之后,而命令A则是将其后输入的字符追加到当前光标所在行的行尾。

  3. 另起新行

    另起新行的命令为o和O,其中命令o是在当前行的下面另起一行,命令O是在当前行的上面另起一行。新行创建完后,光标停留在新行行首,等待输入文字。

  4. 删除字符

    删除字符的命令为x和X。其中命令x删除光标所在处的字符,而命令X删除光标前面的那个字符。如果之前给出一个数字n,则删除由光标所在字符开始向右的n个字符。

  5. 删除文本对象

    命令dd删除光标所在的行,命令D删除从光标所在位置开始到行尾的所有字符。

字母d可以与光标移动命令组合,例如:

  • d^ 从光标位置删至行首,不包括光标位。
  • d$ 从光标位置删至行尾,包括光标位,与D作用相同。
  • dG 删除当前行至文件尾的内容。
  • Dgg 删除当前行至文件头的内容。

# 修改命令

修改文本的命令为cw,C和cc

作用是用新输入的文本取代原来的文本,这等价于将原来的文本删除后,利用命令i插入新的文本。

例如有一字符串:Hello World!

假设光标当前处在e处,输入命令cw后,屏幕显示如下:

H World!

此时光标处在H后的空格处,接着输入文本i后按Esc键,屏幕显示如下:

Hi World!

从上面可以看出,cw只是修改光标当前位置到词尾的字符,如果要修改整个单词,可以使用命令caw。

C命令用来修改从光标位置到行尾的文本。如果在前面加一个数字n,那么会把从当前光标位置至当前行下面的n-1行的内容都删除。

命令cc的功能和C相同,只是修改的范围不同,它修改光标所在的整行内容。

# 取代命令

取代文本的命令为r和R。其中命令r是用其后输入的单个字符取代光标所在的字符,如果在r前加一个数字n,则用其后输入的单个字符取代光标所在处开始向后的n个字符。

R命令用其后输入的文本取代光标所在处开始的若干个字符,每输入一个字符就取代原有的一个字符,多出的部分附加在后面。

# 复制与粘帖

vi编辑器中的缓冲区分为无名缓冲区和命名缓冲区。无名缓冲区以数字编号,一共有9个。前面讲过可以使用删除命令x和dd来删除文本,其实被删除的内容还保存在缓冲区中,最近一次删除的内容被保存在缓冲区1中,次近的在缓冲区2中,以此类推,我们可以使用命令把他们提取回来。

# 粘帖

粘帖缓冲区内容的命令是p和P,这两个命令的区别是:命令p将文本放在当前行之下或当前光标之后,而命令P将文本放在当前行之上或光标之前。

# 复制

命名缓冲区是以字母a~z命名的,利用命名缓冲区可以很好地保存若干文本段,便于以后存取、移动或者重排。访问这些缓冲区时,和前面一样,使用单个双引号。

复制文本的命令有如下两种格式:

  • yy
  • y<光标移动命令>

其中yy表示复制整行内容,而后者则通过光标移动命令来限定被复制的文本,如果没有指定缓冲区的名字,文本就被插入到无名缓冲区中。如果用大写字母表示缓冲区,则文本就附加到该缓冲区中,缓冲区中原有的内容不会被覆盖。

# 不使用缓冲区的复制与移动

使用的命令为co,它的基本格式如下:

:<开始行>,<结束行> co <目标行>
1

这个命令在命令模式下执行,其中开始行和结束行标识了文本复制的范围,而目标行则是文本粘帖的位置。

注:

co 改为 m 即完成剪切复制操作

# 多行删除

:<开始行>,<结束行> d
1

# 查找与替换

# 简单替换表达式

:[range]s/from/to/[flags]

%表示所有行,$表示文件尾,

  • range:搜索范围,如果没有指定范围,则作用于但前行。

    1. 1,10s/from/to/ 表示在第1到第10行(包含第1,第10行)之间搜索替换;
    2. 10s/from/to/ 表示只在第10行搜索替换;
    3. %s/from/to/ 表示在所有行中搜索替换;
    4. 1,$s/from/to/ 同上。
  • flags 有如下四个选项:

    1. c confirm,每次替换前询问;
    2. e error, 不显示错误;
    3. g globle,不询问,整行替换。如果不加g选项,则只替换每行的第一个匹配到的字符串;
    4. i ignore,忽略大小写。

这些选项可以合并使用,如cgi表示不区分大小写,整行替换,替换前询问。

例子

  • 删除行尾空格: %s/\s+$//g
  • 删除行首多余空格: %s/^\s*//
  • 删除第101到200行行首空格:101,200s/^\s\+//
  • 删除第101到200行行前5个字符:101,200s/^.\{5\}//
  • 删除沒有內容的空行:%s/^$// 或者 g/^$/d
  • 删除包含有空格组成的空行:%s/^\s*$// 或者 g/^\s*$/d
  • 删除以空格或TAB开头到结尾的空行:%s/^[ |\t]*$// 或者 g/^[ |\t]*$/d
  • 把文中的所有字符串"abc……xyz"替换为"xyz……abc"可以有下列写法
    • :%s/abc(.*)xyz/xyz\1abc/g
    • :%s/(abc)(.*)(xyz)/\3\2\1/g