Linux 之旅 7:vim 程序编辑器

Linux 之旅 7:vim 程序编辑器

Linux上最常用的文本编辑器是vim,但老实说也很难学,光一个编辑器使用指南就可以写一篇文章,在现在这个软件越来越易用的年代也算是另类了。

尤其是我们还有很多替代方式,比如nano,或者干脆使用图形化的编辑器,比如VSCode的Linux版本,甚至还可以用Windows上的IDE远程连接后进行编辑(以前工作的时候我就是用Zend远程连接修改和debug测试机上的程序的),这都很方便,而且还是你熟悉的工具。

但是vim依然有其存在的价值,比如说因为是命令行程序,可以在各种ssh连接工具上直接调用,而且不依赖于XWindow桌面,像一些出于安全或者性能方面考虑而不安装XWindow的Linux主机,除了用IDE远程连接外就只能使用nano或者vim这样的工具了。

vim的功能显然要远远超过nano

下面介绍vim的使用方式。

vivim

vim是在vi的基础上开发的,比vi更强大,可以看作是vi的增强版,具体来说,主要是增加了编程相关的支持,对于不同的程序语言提供相应的语义颜色显式的支持,这点对开发者非常重要,对于运维来说,同样支持shell脚本的颜色显式。

[icexmoon@xyz ~]$ whereis vi vim
vi: /usr/bin/vi /usr/share/man/man1/vi.1.gz /usr/share/man/man1p/vi.1p.gz
vim: /usr/bin/vim /usr/share/vim /usr/share/man/man1/vim.1.gz
[icexmoon@xyz ~]$ alias vi
alias vi='vim'

虽然CentOS7上同时安装了vivim,但是可以看到存在一个命令别名vi,实质上是调用vim,也就是说默认情况下在bash中执行vi都是使用的vim,如果要调用真正的vi,需要这样:

[icexmoon@xyz tmp]$ \vi test.py
[icexmoon@xyz tmp]$ /bin/vi test.py

使用vi打开一个测试用的python代码,效果是这样的:

Linux 之旅 7:vim 程序编辑器_第1张图片

使用vim打开,效果这样:

Linux 之旅 7:vim 程序编辑器_第2张图片

区别还是很明显的。

为什么要学习vim

除了上边说明的vim存在的意义以外,vim还是很多shell程序调用的默认编辑器,也就是说如果某些应用执行的时候需要编辑一个文本文件,就会直接调用vim来打开该文件,然后让用户编辑,这种情况下你就必须会用vim了,也无法用其它方式去替代。

vi的使用

这里先介绍vi的用法,最后再介绍vim增强的功能,因为它们都是一脉相承,除了增强的功能以外用法都是一样的。

vi最难令初学者理解的地方在于,作为一个文本编辑器,居然还分为三种工作模式,而且一开始打开后并非处于文本编辑模式,你不能随意移动光标编辑文本,这就很让人费解了,我第一次打开的时候完全是莫名其妙。

具体来说是分为以下三种模式:

  • 指令模式(command mode):

    指令模式也是一开始进入程序后的默认模式,在这个模式下可以直接使用各种快捷键对文本进行直接修改,也可以输入一些特殊字符进入命令模式。

  • 输入模式(insert mode):

    在指令模式下输入特殊字符(比如i),后可以进入输入模式,或者叫做编辑模式。

    在这个模式下我们可以像使用普通的文本编辑器那样移动光标,进行删除,或者输入文字。按ESC可以退出到指令模式。

  • 命令行模式(command-line mode):

    在指令模式下输入/?:可以进入命令行模式,前两个符号用于检索,最后一个用于输入命令。

    在命令行下可以输入字符串进行检索,或者是使用各种命令实现各种功能,比如修改vi的相关设置,或者对修改内容进行写入,亦或者退出应用。

    ESC可以返回到指令模式。

三种模式的转换可以用下图表示:

Linux 之旅 7:vim 程序编辑器_第3张图片

(图片来自鸟哥的私房菜)

简易执行范例

打开文件

使用vi filename可以打开一个文件,如果文件不存在,会新建,比如:

Linux 之旅 7:vim 程序编辑器_第4张图片

可以看到,左下角是文件名,以及[New File],表示这是一个新文件。

Linux 之旅 7:vim 程序编辑器_第5张图片

这是一个已经存在的文件,可以看到左下角的信息,表示文件是test.py,只有1行数据,包含23个字符。

进入输入模式

在指令模式下按下i就可以进入输入模式:

Linux 之旅 7:vim 程序编辑器_第6张图片

此时左下角会出现为INSERT字样,并且可以在该模式下移动光标并输入字符。

返回指令模式

这个简单,在输入模式下按ESC即可返回指令模式。

Linux 之旅 7:vim 程序编辑器_第7张图片

进入命令行模式

输入:即可进入命令行模式:

Linux 之旅 7:vim 程序编辑器_第8张图片

此时光标会出现在左下方的:字符之后,然后你就可以在这里输入相关命令并且按下Enter执行,这里我们输入wq以保存修改并退出。

Linux 之旅 7:vim 程序编辑器_第9张图片

使用cat查看修改结果:

[icexmoon@xyz tmp]$ cat test.py
print("hellow wolrd!")
print("end")

这里wq是最长用的保存并退出,如果不想保存,想直接退出,可以q,但如果内容有变更,是不允许你这样离开的,需要使用q!强制退出。如果文件没有写权限,同样是无法执行w命令的,此时如果你是该文件的拥有者或者root用户,可以使用w!强制写入。类似的wq!是强制写入后退出。

以上就是最简单的vi操作流程,当然vi的功能远远不止如此,这在后边详细说明。

按键说明

这里将vi中可以使用的按键和命令按模式划分为三部分:

为了更好地进行vim相关测试,这里下载了我的一个项目以提供文本文件,不过需要先安装工具gitsudo yum install git,如果无法安装的可能还需要替换CentOS的源为国内的源:CentOS配置本地yum源/阿里云yum源/163yuan源,并配置yum源的优先级,当然这并不是必须的,你可以上传自己喜欢的文本到虚拟机中进行测试。

指令模式下可以使用的按键
  • 下边按键中的d>n>G之类的表示依次输入某个按键,比如这个就表示先输入d,再输入一个数字,最后再输入G
  • 下边按键中的未被代码模块包裹的n字母表示输入任意一个数字,比如20。
  • +表示组合键。
按键 作用
h方向键左 向左移动光标
j方向键下 向下移动光标
k方向键上 向上移动光标
l方向键右 向右移动光标
n>l或n>方向键右 向右移动n个字符的光标
Ctrl+fPageDown 向下翻页
Ctrl+bPageUp 向上翻页
Ctrl+d 向下移动半页
Ctrl+u 向上移动半页
+ 移动到非空白字符的下一行行首
- 移动到非空白字符的当前行首
n>空格 移动到n个字符之后
0Home 移动到行首
$End 移动到行尾
H 移动光标到当前页第一行(非空)的行首
M 移动光标到当前页中间行(非空)的行首
L 移动光标到当前页最后一行(非空)的行首
G 移动光标到最后一行
n>G 移动光标到第n
g>g 移动光标到首行,相当于1G
xdelete 删除当前光标之后的一个字符
X 删除当前光标之前的一个字符
n>x 向后删除n个字符
dd 删除光标所在的一整行
n>dd 删除光标以下的n行
d>n>G 删除光标所在行到第n行的所有行
d>g>g 删除光标所在行到第一行的所有行,相当于d1G
d>G 删除光标所在行到最后一行
d>$ 删除光标到行尾的字符,不包含光标所在字符
d>0 删除光标到行首的字符,不包含光标所在字符
y>y 复制光标所在行
n>y>y 向下复制n行
y>n>G 复制到第n行之间的所有行
y>g>g 复制到首行的所有行,相当于y1G
y>G 复制到最后一行之间的所有行
y>0 复制到行首的字符
y>$ 复制到行尾的字符
p 粘贴到光标的下一行
P 粘贴到光标的上一行
J 合并当前行和下一行
u 撤销上一个操作
Ctrl+r 恢复上一个操作
. 重复上一个操作

在我实际尝试后,有这么几个感受:

  • 虽然hjkl这几个键都在一排,但并不像wsad那样结构和方向键一样,反而让人摸不着头脑,还是推荐使用方向键。
  • 同样的道理,相关的翻页还是使用PageDownPageUp更为直观,而且Ctrl+f在某些ssh连接终端本身就被赋予了其它操作,比如查找。
  • 在指令模式下,移动到行尾时,光标并不会真正在最后一个字母后,而是在最后一个字母前,这是因为在指令模式下类似于删除当前字符这种操作,如果光标真的后边啥也没了,就没法操作了,所以光标后边至少有一个字符。
输入模式相关按键

在指令模式中输入以下按键可以进入输入模式:

按键 作用
iI 进入输入模式,且光标停留在当前位置
aA 进入输入模式,且光标停留在下一个字符
oO 进入输入模式,在下一行插入一个空行,且光标停留在行首
r 进入输入模式,在输入一个字符后会替换掉光标之后的字符,并退出
R 进入输入模式,输入的字符会替换掉光标之后的字符
ESC 从输入模式退出到指令模式
命令模式下可以使用的命令
命令 用途
:w 将变更的数据写入文件
:w! 强行写入文件(常用于没有写入权限时)
:q 退出vi
:q! 强行退出(常用于有变更数据,但是不想保存)
:wq 写入变更数据后退出
:wq! 强行写入变更数据后退出
ZZ 若文件没有修改,则不报错退出,若文件有修改,则保存后退出
:w [filename] 将编辑中的内容写入另一个文件(相当于另存为)
:r [filename] 读取指定文件,并将内容插入下一行
:n1,n2 w [filename] 将n1~n2行的数据写入指定文件
! [command] 执行shell命令,执行完后按Enter返回vi界面
:set [vi_set] 设置一些vi的参数,比如:set nu可以显示行号(仅对当前有效)
/[words] 向下查找输入的字符串
?[words] 向上查找输入的字符串
n 下一个查找结果
N 方向查找
:n1,n2s/[words1]/[words2]/g 将第n1行到第n2行的[words1]替换为[words2]
:1,$/[words1]/[words2]/g 将全文中的[words1]替换为[words2]
:1,$/[words1]/[words2]/gc 替换全文的[words1][words2],并在替换是询问用户

一个案例练习

练习案例可以使用鸟哥的私房菜的案例。

练习文本可以这样下载[icexmoon@xyz vitest]$ wget http://linux.vbird.org/linux_basic/03

vim 的缓存文件、恢复与打开时的警告信息

很多文字处理工具都有恢复之前的录入数据的功能,也就是说你还没来得及保存就遇到某些突发事件,比如电脑断电关机或者程序崩溃,在这些情况下依然可以找回还没来得及保存的数据。

我们的vi也可以做到,打开任意文件,修改后不要保存,直接关闭ssh连接,这样就相当于程序非正常终止。然后到文本文件所在的目录看一下:

[icexmoon@xyz vitest]$ ls -al
总用量 36
drwxrwxr-x.  2 icexmoon icexmoon    72 813 17:22 .
drwxrwxrwt. 28 root     root      4096 813 17:23 ..
-rw-rw-r--.  1 icexmoon icexmoon  4850 813 17:15 man_db.conf
-rw-r--r--.  1 icexmoon icexmoon 16384 813 17:22 .man_db.conf.swp
-rw-rw-r--.  1 icexmoon icexmoon  4847 813 17:14 man_test.config

出现了一个.man_db.conf.swp的文件,这个文件就是vi产生的临时文件,用于记录你编辑的还没有保存的信息,自然可以利用这个文件进行恢复。

现在重新用vi打开文件:

E325: ATTENTION
Found a swap file by the name ".man_db.conf.swp"
          owned by: icexmoon   dated: Fri Aug 13 17:22:53 2021
         file name: /tmp/vitest/man_db.conf
          modified: YES
         user name: icexmoon   host name: xyz.icexmoon.centos
        process ID: 5573
While opening file "man_db.conf"
             dated: Fri Aug 13 17:15:56 2021

(1) Another program may be editing the same file.  If this is the case,
    be careful not to end up with two different instances of the same
    file when making changes.  Quit, or continue with caution.
(2) An edit session for this file crashed.
    If this is the case, use ":recover" or "vim -r man_db.conf"
    to recover the changes (see ":help recovery").
    If you did this already, delete the swap file ".man_db.conf.swp"
    to avoid this message.
"man_db.conf" 122L, 4850C
Press ENTER or type command to continue

这里提醒我们文件没有正常退出,并且可以使用:recover命令进行恢复。

Enter打开文件后,进行恢复,然后保存退出:

[icexmoon@xyz vitest]$ ls -al
总用量 36
drwxrwxr-x.  2 icexmoon icexmoon    72 813 17:30 .
drwxrwxrwt. 28 root     root      4096 813 17:28 ..
-rw-rw-r--.  1 icexmoon icexmoon  4832 813 17:30 man_db.conf
-rw-r--r--.  1 icexmoon icexmoon 16384 813 17:22 .man_db.conf.swp
-rw-rw-r--.  1 icexmoon icexmoon  4847 813 17:14 man_test.config
[icexmoon@xyz vitest]$ cat man_db.conf  | head -n 10
#
#
# This file is used by the man-db package to configure the man and cat paths.
# It is also used to provide a manpath for those without one by examining
# their PATH environment variable. For details see the manpath(5) man page.
#
# Lines beginning with `#' are comments and are ignored. Any combination of
# tabs or spaces may be used as `whitespace' separators.
#
# There are three mappings allowed in this file:

文件内容是对了,但是swp文件依然存在,且再次进入后还是会有提示信息,这时候只能手动删除了:

[icexmoon@xyz vitest]$ rm .man_db.conf.swp

vivim的恢复方式和提示信息有所不同,vim有更多的恢复选项:

交换文件 ".man_db.conf.swp" 已存在!
以只读方式打开([O]), 直接编辑((E)), 恢复((R)), 删除交换文件((D)), 退出((Q)), 中止((A)):

这几个选项的用途是:

  • [O](open read-only):用只读方式打开文件,不进行任何编辑操作
  • [E](edit anyway):直接载如当前的文件内容,不理会swp中的未写入的修改内容
  • [R](recover):使用swp中缓存的修改内容进行恢复,同样需要在保存后手动删除swp文件
  • [D](delete it):确定swp缓存文件没用,直接删除该文件
  • [Q](quit):退出
  • [A](abort):忽略并退出,相当于[Q]

vim 的额外功能

前边说了,vim可以看作是vi的增强版:

Linux 之旅 7:vim 程序编辑器_第10张图片

vim打开一个系统配置文件/etc/services,可以看到不仅使用紫色标识注释内容,而且右下角542,18还显示当前光标处于54218列,4%是当前页面的进度占整个文件的长度是4%。

区块选择

vim还支持区块选择,这里我们先下载一个用于练习的文本:

[icexmoon@xyz vitest]$ wget http://linux.vbird.org/linux_basic/0310vi/hosts

按下v之后移动光标,光标经过的内容都将被选定:

Linux 之旅 7:vim 程序编辑器_第11张图片

ESC或再次按v可以取消选定。

V后移动光标可以选定整行:

Linux 之旅 7:vim 程序编辑器_第12张图片

按下Ctrl+v后移动光标可以选定一个矩形区域:

Linux 之旅 7:vim 程序编辑器_第13张图片

之后的操作就和命令模式下对单个字符的操作相同了:

  • y复制
  • d删除
  • p粘贴

这个功能应该用于复制粘贴代码挺有用的,比需要按行号计算需要复制几行,然后nyy这样的操作要直观许多。

多文件编辑

有时候我们在编写代码的时候需要在多个文件之间复制粘贴,也就是多文件编辑,vim同样支持。

使用vim同时打开两个文件:

[icexmoon@xyz note5]$ vim test_v1.py test2_v1.py

vim中输入:files命令:

Linux 之旅 7:vim 程序编辑器_第14张图片

可以看到当前打开了两个文件,且当前显示的是test_v1.py这个文件。

按下V后选择需要复制的代码:

Linux 之旅 7:vim 程序编辑器_第15张图片

y复制,然后输入:n切换到另一个文件:

Linux 之旅 7:vim 程序编辑器_第16张图片

光标移动到最后一行后按p粘贴:

Linux 之旅 7:vim 程序编辑器_第17张图片

然后输入:wq保存离开。

关于多文件编辑的命令也很简单:

  • :files:列出当前打开的所有文件
  • :n:切换到下一个文件
  • :N:切换到上一个文件
  • :e [filename]:打开一个新的文件,并切换到该文件
多窗口功能

有时候我们在写代码的时候需要参考另一个文件,或者是本文件的另一个部分,这时候我们都会将IDE窗口进行拆分,拆分成2个或者更多窗口,可以很方便的一边看另一个地方的代码一边编写当前的代码。

vim同样支持这个功能!

这里打开一个84行的代码,并输入:sp命令:

Linux 之旅 7:vim 程序编辑器_第18张图片

可以看到窗口切分成了2个,且都是显示同一个文件。

现在在上边的窗口中移动到需要复制的代码行,然后选中复制。

按下Ctrl+w,然后再按下

Linux 之旅 7:vim 程序编辑器_第19张图片

此时光标移动到了下边的窗口,然后就可以在需要的地方粘贴复制的代码,或者是参考上边的窗格内容编写代码。

需要注意的是,在WindowsCtrl+w往往是关闭当前窗口的组合键,在Windows Terminal中同样是关闭当前标签页的组合键,如果想屏蔽掉这个快捷键,需要修改WT的相关设置。

在多窗口模式下,要关闭哪个窗口只需要切换到该窗格后使用:q退出即可,不会影响其它窗口。

多窗口功能有以下命令:

  • :sp [filename]:打开指定文件,并用另一个窗口显示,如果没有指定文件,则将当前文件进行拆分显示。
  • Ctrl+w>:切换到上边的窗口
  • Ctrl+w>:切换到下边的窗口
  • :q:退出当前窗口
智能联想

在我们使用IDE编程的时候,往往只需要输入一个函数名的前几个字母,就能关联出完整的函数名,我喜欢将这个功能称作“智能联想”,而vim也具有类似的功能。

具体有以下功能:

组合按钮 补全内容
Ctrl+x>Ctrl+n 依据当前文件的内容进行补全
Ctrl+x>Ctrl+o 依据当前文件类型进行补全,(即根据文件扩展名类型)
Ctrl+x>Ctrl+f 依据当前文件的文件名进行补全

我本来想实际测试的,结果发现依据文件类型补全对python程序不起作用,而Ctrl+n同样是WT的一个快捷键,好麻烦,就不打算继续折腾了,还是IDE好用…

vim环境设置与记录

vim本身支持多种设置:

  • :set nu:显示行号
  • :set nonu:不显示行号
  • :set autoindent:自动缩进
  • :set noautoindent:不自动缩进
  • :set backup:自动备份,开启后使用vim编辑文件会自动生成一个filename~的备份文件。
  • :set ruler:显示状态行(右下角那个行列信息)
  • :set showmode:显示模式信息(左下角)
  • :set backspace=(012):在输入模式下backspace键是否可以删除字符,2表示可以删除任意字符,0或1表示仅能删除新输入的字符。
  • :set all:显示全部设置
  • :set:显示用户修改过的设置
  • :syntax on:开启语法高亮
  • :syntax off:关闭语法高亮
  • :set bg=dark:背景为深色系
  • :set bg=light:背景为浅色系

vim的配置文件为/etc/vimrc,但并不推荐直接修改这个文件,如果需要自定义配置,可以创建~/.vimrc作为自己的vim配置文件:

[icexmoon@xyz note2]$ vim ~/.vimrc
set nu          "显示行`号
set autoindent  "自动缩进
set ruler       "显示状态行
set showmode    "显示模式信息
set bg=dark     "使用深色背景
syntax on       "开启语法高亮

可以使用set nu也可以使用:set no,有没有:不影响效果,注释可以使用"

修改好以后每次使用vim都将使用这里的配置。

常用指令示意图

vim中的常用指令可以参考下图:

Linux 之旅 7:vim 程序编辑器_第20张图片

(图片来资鸟哥的私房菜)

其它 vim 使用的注意事项

中文编码

在使用Linux的时候难免会遇到各种中文乱码的问题,此时就需要排查各种编码和字符集的设置:

  1. 检查Linux系统使用的编码和语言:/etc/locale.conf
  2. 检查bash的编码和语言:环境变量LANGLC_ALL
  3. 检查文件的编码
  4. 使用的应用所用的编码

可以按照上边这个顺序进行排查。

[icexmoon@xyz note2]$ echo $LANG
zh_CN.UTF-8
[icexmoon@xyz note2]$ echo $LC_ALL

DOS与Linux的换行符

Linux的换行符是\n,而Windows的换行符是\r\n,所以以前如果要将Windows上编写的代码部署到Linux上就要处理换行符,否则会导致程序运行不正确。但现在已经没有此类问题了,IDE都会正确地自动处理换行问题。

当然,如果你的确遇到此类问题,可以尝试使用dos2unix这个工具对代码进行转换。

如果没有安装此工具,可以使用yum install dos2unix命令安装。

将Linux格式文件转换为Windows:

[icexmoon@xyz note2]$ cd /tmp
[icexmoon@xyz tmp]$ cp -a /etc/man_db.conf .
[icexmoon@xyz tmp]$ ll man_db.conf
-rw-r--r--. 1 icexmoon icexmoon 5171 1031 2018 man_db.conf
[icexmoon@xyz tmp]$ unix2dos -k man_db.conf
unix2dos: converting file man_db.conf to DOS format ...
[icexmoon@xyz tmp]$ cat -A man_db.conf
# ^M$
#^M$
# This file is used by the man-db package to configure the man and cat paths.^M$
# It is also used to provide a manpath for those without one by examining^M$
# their PATH environment variable. For details see the manpath(5) man page.^M$
#^M$
# Lines beginning with `#' are comments and are ignored. Any combination of^M$
# tabs or spaces may be used as `whitespace' separators.^M$
#^M$
# There are three mappings allowed in this file:^M$
# --------------------------------------------------------^M$
# MANDATORY_MANPATH^I^I^Imanpath_element^M$

上边转换成Windows格式的文件以^M$为结尾,$代表\n,而^M代表\r

转换回去:

[icexmoon@xyz tmp]$ dos2unix -k man_db.conf
dos2unix: converting file man_db.conf to Unix format ...
[icexmoon@xyz tmp]$ cat -A man_db.conf | head -n 10
# $
#$
# This file is used by the man-db package to configure the man and cat paths.$
# It is also used to provide a manpath for those without one by examining$
# their PATH environment variable. For details see the manpath(5) man page.$
#$
# Lines beginning with `#' are comments and are ignored. Any combination of$
# tabs or spaces may be used as `whitespace' separators.$
#$
# There are three mappings allowed in this file:$

编码转换

如果某种编码的文件不能显示或使用,还可以使用icov命令将其转换为可以使用的编码:

[icexmoon@xyz tmp]$ wget http://linux.vbird.org/linux_basic/0310vi/vi.big5
--2021-08-13 19:55:11--  http://linux.vbird.org/linux_basic/0310vi/vi.big5
正在解析主机 linux.vbird.org (linux.vbird.org)... 140.116.44.180
正在连接 linux.vbird.org (linux.vbird.org)|140.116.44.180|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1498 (1.5K) [text/plain]
正在保存至: “vi.big5”

100%[===========================================================================================>] 1,498       --.-K/s 用时 0s

2021-08-13 19:55:23 (24.4 MB/s) - 已保存 “vi.big5” [1498/1498])

[icexmoon@xyz tmp]$ iconv -f big5 -t utf8 -o vi.utf8 vi.big5

打开vi.big5显示乱码,但是vi.utf8可以正常显示。

关于vim相关的内容介绍完了,好像也表示很难?其实编辑器这东西,经常摸自然就熟练了。

谢谢阅读。

你可能感兴趣的:(linux,Linux,vim,vi)