Linux运维——Vim技巧二

Vim技巧

  • 一、管理多个文件
    • 1.1、用缓冲区列表管理打开的文件
    • 1.2、用参数列表将缓冲区分组
    • 1.3、将工作区切分成窗口
    • 1.4、用标签页将窗口分组
    • 1.5、用:edit命令打开文件
    • 1.6、使用:find打开文件
    • 1.7、把文件保存到不存在的目录中
  • 二、动作命令在文档中移动
    • 2.1、区分实际行与屏幕行
    • 2.2、基于单词移动
    • 2.3、对字符进行查找
    • 2.4、操作分隔符的文本对象
    • 2.5、操作文本块的文本对象
    • 2.6、标记位置跳转
    • 2.7、在匹配括号间跳转
    • 2.8、在匹配的关键字间跳转
  • 三、在文件间跳转
    • 3.1、跳转列表
    • 3.2、改变列表
  • 四、寄存器
    • 4.1、用无名寄存器实现删除、复制与粘贴操作
    • 4.2、引用寄存器
    • 4.3、无名寄存器("")
    • 4.4、复制专用寄存器("0)
    • 4.5、有名寄存器("a-"z)
    • 4.6、黑洞寄存器("_)
    • 4.7、系统剪贴板("+)与选择专用寄存器("*)
    • 4.8、表达式寄存器("=)
    • 4.9、其他寄存器
    • 4.10、用寄存器中的内容替换高亮选区的文本
    • 4.11、把寄存器的内容粘贴出来
  • 五、宏
    • 5.1、宏的读取与执行
    • 5.2、加次数回放宏
    • 5.3、在连续的文本行上重复修改
    • 5.4、给宏追加命令
    • 5.5、用迭代求值的方式给列表编号

一、管理多个文件

1.1、用缓冲区列表管理打开的文件

Vim 允许我们同时在多个文件上工作。缓冲区列表记录了一次编辑会话中打开的所有文件。

命令效果
:e[dit] {file}打开文件到新缓冲区(若文件已打开则切换到对应缓冲区
:ene[w]创建新的无名缓冲区
:new水平分割窗口并创建新缓冲区
:vnew垂直分割窗口并创建新缓冲区
:bn[ext]切换到下一个缓冲区
:bp[revious]切换到上一个缓冲区
:bfirst跳转到列表开头
:blast跳转到列表结尾
:b {number}:b {name}通过编号或文件名(支持 Tab 补全)切换缓冲区
:ls:buffers列出所有缓冲区(显示编号、状态、文件名)
状态标记
%当前窗口显示的缓冲区
#轮换文件(可通过 Ctrl+^ 切换)
+已修改未保存
a活动缓冲区(已加载且显示在某个窗口)
:bd[elete]关闭当前缓冲区(若未保存会提示)
:bd {number}关闭指定编号的缓冲区
:bw[ipeout]强制关闭缓冲区(丢弃未保存的修改)
:1,3bd关闭编号 1 到 3 的缓冲区(范围操作)
:w保存当前缓冲区
:w {file}另存为新文件(不改变当前缓冲区关联的文件)
:wa[ll]保存所有已修改的缓冲区
:b#切换到最近访问的缓冲区(相当于 Ctrl+^)
Ctrl+^快速切换当前缓冲区和轮换缓冲区(# 标记的缓冲区)
:set hidden允许隐藏已修改的缓冲区(切换时不强制保存)

缓冲区列表:

vim *.txt # 打开多个.txt文件
:ls  	  # 查看缓冲区列表# 结果如下1 %a   "a.txt"                        line 12      "b.txt"                        line 0:bn   # 切换到列表中的下一个缓冲区
:ls# 结果如下1 #    "a.txt"                        line 12 %a   "b.txt"                        line 1# % 符号指明哪个缓冲区在当前窗口中可见, 而 # 符号则代表轮换文件。

使用缓冲区列表:

命令效果
:bn[ext]切换到下一个缓冲区
:bp[revious]切换到上一个缓冲区
:bfirst跳转到列表开头
:blast跳转到列表结尾
:b {number}:b {name}通过编号或文件名(支持 Tab 补全)切换缓冲区
:bufdo在:ls列出的所有缓冲区上执行Ex命令

删除缓冲区:

# 语法
:bdelete N1 N2 N3
:N,M bdelete

删除一个缓冲区并不会影响缓冲区所关联的文件,而只是简单地把该文件在内存中的映像删掉。如果我们想删除编号 5~10(包含 5 和 10)的缓冲区,可以执行 :5,10bd; 然而, 如果想要保留编号为 8 的缓冲区的话, 那么就只能用 :bd 5 6 7 9 10 了。

1.2、用参数列表将缓冲区分组

  • 参数列表(args)​​
    • 通过命令行或 :args 命令指定的一组文件,Vim 会将这些文件加载到缓冲区列表,但不会立即全部打开(按需加载)。
  • ​与缓冲区列表的区别​:
    • ​缓冲区列表(:buffers)​​:包含所有已打开的文件(包括通过 :e 手动打开的)。
    • 参数列表(:args)​​:仅包含启动时或显式指定的文件集合,适合批量操作。

初始化参数列表:

# 启动时指定
vim file1.txt file2.txt  # 启动时传入参数列表# 在Vim中修改参数列表
:args *.txt           " 将当前目录下所有 .txt 文件加入参数列表
:args file1.js file2.js " 手动指定文件
:args `find . -name "*.md"` " 通过反引号命令动态生成列表(需支持 shell)

查看参数列表:

:args                  " 显示当前参数列表
:arglist               " 同上# 输出示例 [] 表示当前正在编辑的参数文件
[file1.txt] file2.txt file3.js 

切换参数文件:

:next (:n)             " 切换到下一个参数文件
:prev (:prev)          " 切换到上一个参数文件
:first (:first)        " 跳转到第一个参数文件
:last (:last)          " 跳转到最后一个参数文件
:argadd file4.txt      " 向参数列表追加文件
:argdel file2.txt      " 从参数列表中删除文件

批量操作:

:argdo %s/foo/bar/g    " 在所有参数文件中替换 'foo' 为 'bar'
:argdo update          " 保存所有修改过的参数文件
:argdo set ft=python   " 对所有参数文件设置文件类型为 Python

用Glob模式指定文件:

Glob模式所匹配的文件
:args *.*index.html
app.js
:args **/*.jsapp.js
lib/framework.js
app/controllers/Mailer.js
…etc
:args **/*.*app.js
index.html
lib/framework.js
lib/theme.css
app/controllers/Mailer.js
…etc

管理隐藏缓冲区:

Vim 对被修改过的缓冲区会给予特殊对待,以防未加保存就意外退出。

vim *.txt    # 打开a.txt b.txt
:ls 		 # 查看缓冲区列表# 结果1 %a   "a.txt"                        line 12      "b.txt"                        line 0

首先,我们对 a.txt 做点修改,按 Go 在缓冲区的结尾增加一个空行。先不要保存修改,让我们查看一下当前的缓冲区列表:

  1 %a + "a.txt"                        line 172      "b.txt"                        line 0

缓冲区 a.txt 前有一个 + 号,表示这个缓冲区被修改过了。如果现在保存文件的话, 缓冲区的内容就会被写入磁盘里, 而 + 号也会消失了。 但是我们先不急着保存,而是试着切换一下缓冲区:

:bn# 结果
E37: No write since last change (add ! to override)

此时,Vim 会弹出一条错误信息,说当前缓冲区中有未保存的改动。让我们试一下括号中的建议,在上述命令的结尾加一个叹号:

:bn!
:ls# 结果1 #h + "a.txt"                        line 172 %a   "b.txt"                        line 1

叹号会强制 Vim 切换缓冲区,即使当前缓冲区中有未保存的修改,也会继续切换。如果现在再运行 :ls 命令,就会发现 b.txt 被标记为 a,表示它当前是活动缓冲区(active) ,而 a.txt 则被标记为 h,表示它是一个隐藏缓冲区(hidden)。

在退出时处理隐藏缓冲区:

当一个缓冲区被隐藏后,Vim 允许我们像往常一样工作。我们可以打开其他缓冲区,对其进行修改、保存等,没有任何不同。也就是说,一直到尝试退出编辑会话前,一切如常。然而,当我们想关闭编辑会话时,Vim 就会提醒我们某个缓冲区中有未保存的修改:

:qE37: No write since last change
E162: No write since last change for buffer "a.txt"

Vim 会把第一个有改动的隐藏缓冲区载入当前窗口,这样我们就可以决定如何处理它。如果要保留修改,可以执行 :write 命令把缓冲区保存到文件;如果想摒弃此修改,可以执行 :edit!,重新从磁盘读取此文件,这会用文件的内容覆盖缓冲区中的内容。当缓冲区内容与磁盘文件一致后,我们就可以再次尝试执行 :quit 命令了。

如果会话里有不止一个被修改过的隐藏缓冲区,那么每次执行 :quit 命令时,Vim 都会激活下一个未保存的缓冲区。同样的,我们可以用 :write:edit! 来保存或摒弃此修改。当没有其他窗口和隐藏缓冲区时,:q 命令就会关闭 Vim。

如果想退出 Vim 而不想对未保存的修改进行检查,可以执行 :qall! 命令;如果想保存所有有改动的缓冲区而无需逐个检查,可以用 :wall 命令。

命令用途
:w[rite]把缓冲区内容写入磁盘
:e[dit]!把磁盘文件内容读入缓冲区(即回滚所做修改)
:qa[ll]!关闭所有窗口,摒弃修改而无需警告
:wa[ll]!把所有改变的缓冲区写入磁盘

1.3、将工作区切分成窗口

Vim 允许我们将工作区切分成若干窗口,在这些窗口里并排显示多个缓冲区。

创建分割窗口:

Vim 在启动时只会打开单个窗口。用 <C-w>s 命令可以水平切分此窗口,使之成为两个高度相同的窗口;或者可以用 <C-w>v 命令对其进行垂直切分,这样会产生两个宽度相同的窗口。这两条命令可以重复任意多次,结果就会把工作区一次次地切分为更小的窗口,就像细胞分裂那样。

在这里插入图片描述

每次执行完 <C-w>s<C-w>v 命令后,新生成的两个窗口都会显示与原窗口相同的缓冲区。把同一缓冲区显示在不同窗口里会很有用,特别是在编辑长文件时。举个例子,我们可以滚动其中一个窗口,使之显示缓冲区的一部分,这样,在修改第二个窗口中缓冲区的另外一部分时,就可以参考第一个窗口中的内容。

我 们 可 以 用 :edit 命 令 把 另 外 一 个 缓 冲 区 载 入 活 动 窗 口 中 。 如 果 先 执 行<C-w>s,再执行 :edit {filename},就会把工作区分成两个窗口,并在其中一个窗口中打开新缓冲区,而另一个窗口则继续显示原有的缓冲区。另外一种做法是使用 :split {filename} 命令,它把上述两步合并成为了一步。下表总结了把工作区切分为窗口的几种方式:

命令用途
<C-w>s水平切分当前窗口,新窗口仍显示当前缓冲区
<C-w>v垂直切分当前窗口,新窗口仍显示当前缓冲区
:sp[lit] {file}水平切分当前窗口,并在新窗口中载入{file}
:vsp[lit] {file}垂直切分当前窗口,并在新窗口中载入{file}

在窗口间切换:

命令用途
<C-w>w在窗口间循环切换
<C-w>h切换到左边的窗口
<C-w>j切换到下边的窗口
<C-w>k切换到上边的窗口
<C-w>l切换到右边的窗口

关闭窗口:

Ex命令普通模式命令用途
:clo[se]c`关闭活动窗口
:on[ly]o`只保留活动窗口,关闭其他所有窗口

改变窗口大小及重新排列窗口:

命令用途
<C-w>=使所有窗口等宽、等高
<C-w>_最大化活动窗口的高度
``
[N]<C-w>_把活动窗口的高度设为[N]行
`[N]`

1.4、用标签页将窗口分组

打开及关闭标签页:

命令用途
:tabe[dit] {filename}在新标签页中打开 {filename}
<C-w>T把当前窗口移到一个新标签页
:tabc[lose]关闭当前标签页及其中的所有窗口
:tabo[nly]只保留活动标签页, 关闭所有其他标签页

在标签页间切换:

标签页的编号从 1 开始, 我们可以用 {N}gt 命令在标签页间切换,可以把此命令记成“跳到标签页{N}” 。当此命令带一个数字前缀时,Vim 会跳到指定编号的标签页;如果省略了数字前缀,则会跳到下一个标签页。 gT 命令的功能与此相同,只是跳转方向相反。

Ex 命令普通模式命令用途
:tabn[ext] {N}{N}gt切换到编号为 {N} 的标签页
:tabn[ext]gt切换到下一标签页
:tabp[revious]gT切换到上一标签页

重拍标签页:

:tabmove [N] 命令可以重新排列标签页。当 [N] 为 0 时,当前标签页会被移到开头;如果省略了 [N],当前标签页会被移到结尾。如果你的终端支持鼠标,或是你正在使用 GVim,那么你也可以通过鼠标拖曳来进行重排操作。

1.5、用:edit命令打开文件

在 Vim 中,:edit 命令允许通过文件的绝对路径或相对路径来打开文件。

相对于当前工作目录打开一个文件:

:edit {file} 命令可以接受相对于工作目录的文件路径。

:edit lib/framework.js
:edit app/controllers/Navigation.js

相对于活动文件目录打开一个文件:

假设我们正在编辑 app/controllers/Navigation.js,紧接着我们要编辑同一目录下的 Main.js。一种做法是输入从工作目录开始的路径,直到抵达该文件,然而这似乎有点儿舍近求远。

:edit %<Tab>
# % 符号代表活动缓冲区的完整文件路径
# 按 <Tab>键会将其展开,使之显示为活动缓冲区的完整文件路径。
# 虽然这不是我们想要的结果,但是已经很接近了。:edit %:h<Tab>
# :h 修饰符会去除文件名,但保留路径中的其他部分
# 在此例中,输入的 %:h<Tab> 会被展开为当前文件所在目录的路径,即 app/controllers/:edit %:h<Tab>M<Tab>
# 后续输入M,再<Tab>键补全全文件名

1.6、使用:find打开文件

:find 命令允许我们通过文件名打开一个文件,但无需输入该文件的完整路径。要想利用此功能,我们首先要配置 ‘path’ 选项。

配置path选项:
'path' 选项允许我们指定一些目录,当调用 :find 命令时,Vim 会在这些目录中进行查找 。在本例中,我们想让 app/controllersapp/views 目录下的文件更容易被找到,因此可以执行下面的命令,把这些目录加入到查找路径中:

# ** 通配符会匹配 app/ 目录下的所有子目录。
:set path+=app/**

使用:find命令,通过文件名查找文件:

如果想打开 app/controllers/Navigation.js文件,我们可以输入这条命令:

:find Navigation.js

1.7、把文件保存到不存在的目录中

即使缓冲区的路径中包含了不存在的目录, Vim 仍允许我们对该缓冲区进行编辑,只是在我们试图将缓冲区写入文件时,Vim 会报错。

:edit {file} 命令一般用于打开一个已存在的文件。然而,如果我们指定了一个不存在的文件路径,那么 Vim 就会创建一个新的空白缓冲区。如果我们此时按<C-g> ,就会看到该缓冲区被标识为“新文件” ( 命令用于显示当前文件的文件名及状态 ) 。随后,当我们执行 :write 命令时,Vim 就会尝试将此缓冲区的内容写到创建该缓冲区时所指定的文件路径中。

如果在执行 :edit {file} 时所指定的文件路径中包含尚未存在的目录,事情就会变得有点棘手。这种情况下,我们可以调用外部的 mkdir 程序对此做出补救:

:!mkdir -p %:h
:write

二、动作命令在文档中移动

2.1、区分实际行与屏幕行

与许多文本编辑器不同, Vim 会区分实际行与屏幕行。当 ‘wrap’ 设置被启用时(缺省启用) ,每个超出窗口宽度的文本行都会被回绕显示,以保证没有文本显示不出来。这样一来,文件中的一行也许会被显示为屏幕上的若干行。

要想知道实际行与屏幕行之间的不同,最简单的方法是启用 ‘number’ 设置。启用后,以行号开头的行对应着一个实际行,它们会占据着屏幕上的一行或几行;当一行文本为适应窗口宽度而回绕时,回绕行的前面则不会显示行号。

命令光标动作
j向下移动一个实际行
gj向下移动一个屏幕行
k向上移动一个实际行
gk向上移动一个屏幕行
0移动到实际行的行首
g0移动到屏幕行的行首
^移动到实际行的第一个非空白字符
g^移动到屏幕行的第一个非空白字符
$移动到实际行的行尾
g$移动到屏幕行的行尾

2.2、基于单词移动

命令光标动作
w正向移动到下一单词的开头
b反向移动到当前单词/上一单词的开头
e正向移动到当前单词/下一单词的结尾
ge反向移动到上一单词的结尾
ea在当前单词结尾后添加

2.3、对字符进行查找

命令作用
f{char}正向移动到下一个 {char} 所在之处
F{char}反向移动到上一个 {char} 所在之处
t{char}正向移动到下一个 {char} 所在之处的前一个字符上
T{char}反向移动到上一个 {char} 所在之处的后一个字符上
;正向跳转到下一个匹配的字符
,反向跳转到上一个匹配的字符

示例:删除,到.之间的文本

按键操作缓冲区内容
{start}I’ve been expecting you, Mister Bond.
f,I’ve been expecting you, Mister Bond.
dt.I’ve been expecting you.

2.4、操作分隔符的文本对象

文本对象允许我们操作括号、 被引用的文本、 XML 标签以及其他文本中的常见结构。

Vim 的文本对象由两个字符组成,第一个字符永远是 i 或是 a。我们一般说,以 i 开头的文本对象会选择分隔符内部的文本,而以 a 开头的文本对象则会选择包括分隔符在内的整个文本。为了便于记忆,可以把 i 想成“inside” ,而把 a 想成
“around” 或“all”。

文本对象选择区域
a)ab一对圆括号 (parentheses)
i)ib圆括号 (parentheses) 内部
a}aB一对花括号 {braces}
i}iB花括号 {braces} 内部
a]一对方括号 [brackets]
i]方括号 [brackets] 内部
a>一对尖括号 <angle brackets>
i>尖括号 <angle brackets> 内部
a'一对单引号 ‘single quotes’
i'单引号 ‘single quotes’ 内部
a"一对双引号 “double quotes”
i"双引号 “double quotes” 内部
a`一对反引号 backticks
i`反引号 backticks 内部
at一对 XML 标签 <xml>tags</xml>
itXML 标签内部

示例:

按键操作缓冲区内容
vi}在这里插入图片描述
va"在这里插入图片描述
vi>在这里插入图片描述
vit在这里插入图片描述
vat在这里插入图片描述
va]在这里插入图片描述

用文本对象执行操作:

每当在命令语法里看到{motion} 时,你也可以在这个地方使用文本对象,常见的例子包括 d{motion}c{motion}y{motion}

示例:将下面文本中的{url}替换为#,然后再用一个
文本标记把{title}替换掉

按键操作缓冲区内容
{start}在这里插入图片描述
ci"#<Esc>在这里插入图片描述
citclick here<Esc>在这里插入图片描述

2.5、操作文本块的文本对象

文本对象选择范围
iw当前单词
aw当前单词及一个空格
iW当前字串
aW当前字串及一个空格
is当前句子
as当前句子及一个空格
ip当前段落
ap当前段落及一个空行

示例:删除下句中的单词“excellent” ,此时可以用 daw 命令

按键操作缓冲区内容
{start}在这里插入图片描述
daw在这里插入图片描述

示例:把此单词改成另外一个单词,这次可以用 ciw 命令

按键操作缓冲区内容
{start}在这里插入图片描述
ciwmost<Esc>在这里插入图片描述

2.6、标记位置跳转

m{a-zA-Z} 命令会用选定的字母标记当前光标所在位置。小写位置标记只在每个缓冲区里局部可见,而大写位置标记则全局可见。

`{a-zA-Z} 命令则把光标移动到设置此位置标记时光标所在之处。

自动位置标记:

位置标记跳转到
``当前文件中上次跳转动作之前的位置
`.上次修改的地方
`^上次插入的地方
`[上次修改或复制的起始位置
`]上次修改或复制的结束位置
`<上次高亮选区的起始位置
`>上次高亮选区的结束位置

2.7、在匹配括号间跳转

Vim 提供了一个动作命令, 让我们可以在开、 闭括号间跳转。 在激活了 matchit.vim插件后,此命令也可以用于成对的 XML 标签,以及某些编程语言中的关键字上。

按键操作缓冲区内容
{start}在这里插入图片描述
%在这里插入图片描述
h在这里插入图片描述
%在这里插入图片描述
l在这里插入图片描述
%在这里插入图片描述

示例:把 %w{London Berlin New\ York} 改 成 普 通 的 列 表 定 义 [“London”,“Berlin”, “New York”],因此要把大括号改成方括号

按键操作缓冲区内容
{start}在这里插入图片描述
dt{在这里插入图片描述
%在这里插入图片描述
r]在这里插入图片描述
``在这里插入图片描述
r[在这里插入图片描述

2.8、在匹配的关键字间跳转

Vim 在发布时带了一个名为 matchit 的插件,它增强了 % 命令的功能。激活此插件后, % 命令就可以在配对的关键字间跳转。例如,在一个 HTML 文件里,用 % 命令 可 以 在 开 标 签 和 闭 标 签 间 跳 转 ; 在 一 个 Ruby 文 件 里 , 可 以 用 它 在 配 对 的class/end、def/end,以及 if/end 间跳转。

# 启动时自动加载matchit插件
set nocompatible
filetype plugin on
runtime macros/matchit.vim

示例:把New York放在双引号里

按键操作缓冲区内容
{start}在这里插入图片描述
vee在这里插入图片描述
S"在这里插入图片描述

三、在文件间跳转

3.1、跳转列表

Vim 会记录跳转前后的位置,并提供了一些命令让我们能够沿原路返回。

命令作用
<C-o>后退
<C-i>前进
:jumps查看那跳转列表

任何改变当前窗口中活动文件的命令,都可以被称为跳转命令。Vim 会把执行跳转命令之前和之后的光标位置,记录到跳转列表中。

命令用途
[count]G跳转到指定的行号
/pattern<CR>/?pattern<CR>/n/N跳转到下一个/上一个模式出现之处
%跳转到匹配的括号所在之处
(/)跳转到上一句/下一句的开头
{/}跳转到上一段/下一段的开头
H/M/L跳到屏幕最上方/正中间/最下方
gf跳转到光标下的文件名
<C-]>跳转到光标下关键字的定义之处
’{mark}/`{mark}跳转到一个位置标记

3.2、改变列表

每当对文档做出修改后,Vim 都会记录当时光标所在的位置。

命令作用
g;方向跳转
g,正向跳转
:changes查看改变列表

四、寄存器

4.1、用无名寄存器实现删除、复制与粘贴操作

调换字符:

按键操作缓冲区内容
{start}Practical lvim
F空格Practica lvim
xPracticalvim
pPractical vim

将最后两条命令组合在一起,即 xp,可被用于“调换光标之后的两个字符” 。

调换文本行:

按键操作缓冲区内容
{start}在这里插入图片描述
dd在这里插入图片描述
p在这里插入图片描述

把以上命令序列连起来,即ddp,可被用于“调换当前行和它的下一行” 。

4.2、引用寄存器

Vim 的删除、复制与粘贴命令都会用到众多寄存器中的某一个。我们可以通过给命令加 "{register} 前缀的方式指定要用的寄存器。若不指明,Vim 将缺省使用无名寄存器。

普通模式中,如果我们想把当前单词复制到寄存器 a中,可执行 "ayiw,或者,可以用 "bdd,把当前整行文本剪切至寄存器 b 中。在此之后,我们既可以输入 "ap粘贴来自寄存器 a的单词,也可使用 "bp命令粘贴来自寄存器 b的一整行文本,两者互不干扰。

命令模式中,可以执行 :delete c,把当前行剪切到寄存器 c,然后再执行 :put c 命令将其粘贴至当前光标所在行之下。

4.3、无名寄存器(“”)

倘若我们没有指定要使用的寄存器,Vim 将缺省使用无名寄存器,它可以用双引号表示。为了显式地引用该寄存器,我们得使用两个双引号。例如,""p,它完全等同于 p命令。

xsd{motion}c{motion}y{motion} 命令(以及它们对应的大写命令)都会覆盖无名寄存器中的内容。

4.4、复制专用寄存器("0)

当我们使用 y{motion} 命令时,要复制的文本不仅会被拷贝到无名寄存器中,而且也被拷贝到了复制专用寄存器中,后者可用数字 0加以引用。

按键操作缓冲区内容
yiw在这里插入图片描述
jww在这里插入图片描述
diw在这里插入图片描述
"0P在这里插入图片描述

4.5、有名寄存器("a-"z)

Vim 提供了一组以26 个英文字母命名的有名寄存器。这意
味着我们可以剪切( "ad{motion}) 、复制("ay{motion})或者粘贴("ap)多达26 段文本。

用小写字母引用有名寄存器,会覆盖该寄存器的原有内容,而换用大写字母的话,则会将新内容添加到该寄存器的原有内容之后。

4.6、黑洞寄存器("_)

黑洞寄存器是个有去无回的地方,可用下划线引用它。如
果我们运行 "_d{motion} 命令,Vim 将删除该文本且不保存任何副本。

当我们只想删除文本却不想覆盖无名寄存器中的内容时,此命令很管用。

4.7、系统剪贴板(“+)与选择专用寄存器(”*)

Vim 的加号寄存器与系统剪贴板等效,可用 + 号引用。

如果我们在外部程序中用剪切或复制命令获取了文本,就可以通过 "+p 命令(或在插入模式下用 <C-r>+)将其粘贴到 Vim 内部。相反地,如果在 Vim 的复制或删除命令之前加入 "+ ,相应的文本将被捕获至系统剪贴板。

4.8、表达式寄存器("=)

Vim 的寄存器通常被认为是保存一段文本的容器。 然而, 通过 = 号引用的表达式寄存器却是个例外。当我们从表达式寄存器获取内容时,Vim 将跳到命令行模式,并显示提示符“=” 。这时,我们可以输入一段 Vim 脚本表达式并按 <CR> 执行,如果返回的是字符串(或者可被强制转换成字符串的数据) ,Vim 将会使用它。

4.9、其他寄存器

Vim 还提供了几组可被隐式赋值的寄存器。它们被称作只读寄存器:

寄存器内容
"%当前文件名
"#轮换文件名
".上次插入的文本
":上次执行的Ex命令
"/上次查找的模式

4.10、用寄存器中的内容替换高亮选区的文本

在可视模式下使用 p命令时,Vim 将用我们指定的寄存器内容来替换高亮选区中的文本。

按键操作缓冲区内容
yiw在这里插入图片描述
jww在这里插入图片描述
ve在这里插入图片描述
p在这里插入图片描述

交换两个词:改为“fish and chips

按键操作缓冲区内容
{start}在这里插入图片描述
fc在这里插入图片描述
de在这里插入图片描述
mm在这里插入图片描述
ww在这里插入图片描述
ve在这里插入图片描述
p在这里插入图片描述
`m在这里插入图片描述
P在这里插入图片描述

4.11、把寄存器的内容粘贴出来

普通模式下的粘贴命令,根据要插入文本的性质不同,执行结果也不同。确定要粘贴的文本区域是面向行的还是面向字符的,将有助于我们制定不同的策略。

  • p命令旨在将寄存器中的文本粘贴到光标之后
  • P命令用于将文本插入到光标之前
  • <C-r>{register}总会被插入至光标之前

粘贴面向字符的区域:

按键操作缓冲区内容
yiw在这里插入图片描述
jww在这里插入图片描述
ciw<C-r>0<Esc>在这里插入图片描述
使 用 ciw 命 令 带 来 的 额 外 好 处 是 , 此 时 用. 命 令 可 以 把 当 前 单 词 替 换 为“collection”。

粘贴面向行的区域:

按键操作缓冲区内容
yap在这里插入图片描述
gP在这里插入图片描述

五、宏

5.1、宏的读取与执行

宏允许我们把一段修改序列录制下来,用于之后的回放。

把命令序列录制成宏:

q 键既是“录制”按钮,也是“停止”按钮。为了录制我们的按键操作,一开始需要按 q{register},从而指定一个用于保存宏的寄存器。当状态栏中出现“记录中”时,表示录制已经开始。此后,我们执行的每一条命令都将被宏捕获,直到我们再次按下 q键停下为止。

按键操作缓冲区内容
qa在这里插入图片描述
A;<Esc>在这里插入图片描述
Ivar空格<Esc>在这里插入图片描述
q在这里插入图片描述

可以通过以下命令查看寄存器 a 中的内容:

:reg a# 结果
Type Name Contentc  "a   A;^[<80><fd>5Ivar ^[<80><fd>5

通过执行宏来回放命令序列:

我们可以用@{register} 命令执行指定寄存器的内容,也可以用@@ 来重复最近调用过的宏。

按键操作缓冲区内容
{start}在这里插入图片描述
j在这里插入图片描述
@a在这里插入图片描述
j@@在这里插入图片描述
通过执行这个刚刚录制好的宏,Vim 对随后的每一行也重复了这两处相同的修改。

5.2、加次数回放宏

例如,有文本如下:

var foo = "method("+argument1+","+argument2+")";

准备把它变成这样:

var foo = "method(" + argument1 + "," + argument2 + ")";
按键操作缓冲区内容
{start}在这里插入图片描述
f+在这里插入图片描述
s空格+空格<Esc>在这里插入图片描述
qq;.q在这里插入图片描述
22@q在这里插入图片描述

在本例中,我们打算将这个宏执行 10 次。但如果回放 11 次的话,最后一次执行将会被中止。换句话说,只要我们用大于或等于 10 的次数调用该宏就可以完成任务了。

5.3、在连续的文本行上重复修改

对于多行范围内的重复性改动,可以先录制一个宏,然后再在每一行上回放,这将会极大减轻我们的工作量。该功能可用两种执行宏的方式实现,串行或者并行。

1. one
2. two
3. three
4. four# 转换为
1) One
2) Two
3) Three
4) Four

录制工作单元:

按键操作缓冲区内容
qa在这里插入图片描述
0f.在这里插入图片描述
r)在这里插入图片描述
w~在这里插入图片描述
j在这里插入图片描述
q在这里插入图片描述

以串行方式执行宏:

可以调用 3 次 @a 命令完成这次任务,但运行 3@a 会更快:

按键操作缓冲区内容
{start}在这里插入图片描述
3@a在这里插入图片描述

但是串行执行可能会遇到问题,假设即将要处理的文本中,会时不时地被注释行所隔断:

1. one
2. two
// break up the monotony
3. three
4. four

在这种情况下,宏在执行到第 3 行时停了下来,所以需要采用并行执行方式。

以并行方式执行宏:

按键操作缓冲区内容
qa在这里插入图片描述
0f.r)w~在这里插入图片描述
q在这里插入图片描述
jVG在这里插入图片描述
:'<,'>normal @a在这里插入图片描述

5.4、给宏追加命令

有时候,我们在录制宏的过程中会漏掉某个至关重要的步骤。在这种情况下,我们没必要从头开始重录所有的步骤,而是可以在现有宏的结尾附加额外的命令。

在我们输入 qa时,Vim 将开始录制接下来的按键操作,并将它们保存到寄存器 a中,这会覆盖该寄存器原有的内容。如果我们输入的是 qA 的话,Vim 也会录制按键操作,但会把它们附加到寄存器 a原有的内容之后。我们可以用这种方式更正该错误。

5.5、用迭代求值的方式给列表编号

假设我们要为一些连续的项目进行编号,以下列文本作为演示:

partridge in a pear tree
turtle doves
French hens
calling birds
golden rings# 转换为
1) partridge in a pear tree
2) turtle doves
3) French hens
4) calling birds
5) golden rings
  • :let命令可以创建变量
  • :echo命令可以查看变量
  • <C-r>-i<CR>可以插入变量i的值

录制宏:

按键操作缓冲区内容
:let i=1在这里插入图片描述
qa在这里插入图片描述
I<C-r>=i<CR>)空格<Esc>在这里插入图片描述
:let i += 1在这里插入图片描述
q在这里插入图片描述

执行宏:

:normal @a 命令将指示 Vim 在高亮选中的每一行上执行这个宏。i 的初始值是 2,但它在每次宏执行完后都会递增。最终,每行都以连续的数字开头了。

按键操作缓冲区内容
{start}在这里插入图片描述
jVG在这里插入图片描述
:'<,'>normal @a在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81801.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年 408 真题及答案

2025 年 408 真题 历年408真题及答案下载直通车 1、以下 C 代码的时间复杂度是多少&#xff1f;&#xff08;&#xff09; int count 0; for (int i0; i*i<n; i)for (int j0; j<i; j)count;A O(log2n)B O(n)C O(nlogn)D O(n2) 2、对于括号匹配问题&#xff0c;符号栈…

【MuJoCo仿真】开源SO100机械臂导入到仿真环境

主要参考&#xff1a;https://github.com/jpata/gym-so100/tree/integration/gym_so100/assets/trs_so_arm100 参考&#xff1a;&#xff08;八&#xff09;lerobot开源项目扩展so100的仿真操控&#xff08;操作记录&#xff09;_so100机械臂 仿真-CSDN博客 下载&#xff1a;…

Socat 用法详解:网络安全中的瑞士军刀

Socat 用法详解&#xff1a;网络安全中的强大工具 引言 socat&#xff08;SOcket CAT&#xff09;是一款功能强大的命令行工具&#xff0c;被誉为“网络瑞士军刀”&#xff0c;广泛应用于数据传输、端口转发和网络调试等场景。它支持多种协议和数据通道&#xff08;如文件、管…

永磁同步电机控制算法--基于PI和前馈的位置伺服控制

一、原理介绍 永磁同步伺服系统是包含了电流环、速度环和位置环的三环控制系统。 伺服系统通过电流检测电路和光电编码器检测电动机三相绕组电流和转子位置θ&#xff0c;通过坐标变换&#xff0c;计算出转矩电流分量iq和励磁电流分量id。 位置信号指令与实际转子位置信号的差…

Lucene多种数据类型使用说明

Lucene 作为一款高性能的全文检索引擎库&#xff0c;其核心功能围绕索引和搜索文本数据&#xff0c;但它也支持多种数据类型以满足复杂的应用场景。以下是 Lucene 支持的主要数据类型及其用途的详细说明&#xff1a; 1. 文本类型&#xff08;Text&#xff09; 用途&#xff1a;…

Web网页布局

目录 一、传统的DIVCSS布局&#xff08;使用率最高的&#xff09; 1.div传统的一块块转 2.以猫眼电影为例‘ 3.div布局格式&#xff08;唯一的id属性&#xff0c;不唯一写class重复的&#xff09; 3.2总体布局样式 二、HTML5语义标签CSS3布局 1.把div改为绿色的语义标签…

大模型基础(五):transformers库(下):快速分词器、自动配置类、快速微调

transformers库&#xff08;下&#xff09; 1 快速分词器1.1 Fast 分词器的核心特点1.2 对比示例1.3 何时使用 Fast 分词器&#xff1f;1.4 注意事项 2 自动配置类 AutoConfig2.1 核心功能2.2 基本用法2.3 主要应用场景2.4 常用函数2.5 与具体配置类的区别2.6 注意事项 3 快速微…

在pycharm profession 2020.3上离线安装.whl类型的包(以PySimpleGUI为例)

今天写个小代码&#xff0c;用到了PySimpleGUI。 在pycharm profession 2020.3的项目中的Terminal里运行如下代码即可安装。 python3 -m pip install --force-reinstall --extra-index-url https://PySimpleGUI.net/install PySimpleGUI 安装方法如图&#xff1a; 安装后使用…

SpringBoot整合RabbitMQ(Java注解方式配置)

1.生产端 1. 创建生产者SpringBoot工程 2. 引入start&#xff0c;依赖坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 3. 编写yml配置&#xff0c;基本…

分析strtol(),strtoul()和strtod()三个函数的功能

字符串转换为数值部分和子字符串首地址的函数有strtol(),strtoul()和strtod()三个函数。 1、strtol()函数 long int strtol(const char *str, char **endptr, int base) //当base0时,若字符串不是以"0","0x"和"0X"开头,则将数字部分按照10进制…

Spring 的事务隔离

在Spring框架中&#xff0c;事务管理是一个非常重要的方面&#xff0c;它允许开发者以声明式的方式定义事务边界&#xff0c;并且通过配置不同的隔离级别来控制并发事务的行为。Spring支持多种事务管理方式&#xff0c;包括编程式事务管理和声明式事务管理&#xff08;如使用Tr…

单片机自动排列上料控制程序

/****L2233 CODE11549 2025 4 18 08:53*******/ /***轴承上料机控制 提升 摇摆 光电检测***/ /***2025 3 21 电机控制PCB板 PAST ***/ /*2.3 2.2 1.2 1.3 1.4 1.5 1.6 1.7 5.3 3.2 ***/ /*启动 解锁 光电 接近 前停 后停 电机前 电机后*/ #include &quo…

力扣119题解

记录 2025.5.5 题目&#xff1a; 思路&#xff1a; 代码: class Solution {public List<Integer> getRow(int rowIndex) {List<Integer> row new ArrayList<Integer>();row.add(1);for (int i 1; i < rowIndex; i) {row.add((int) ((long) row.get(i…

国产化海光C86架构服务器安装windows实录

最近几年与红蓝关系急转直下&#xff0c;尤其是科技领域尤为突出。随之而来的就是软硬件的国产化大潮。由于行业的原因根据要求必须使用国产化服务器、国产化操作系统、国产化数据库、国产化中间件。虽然闭关锁国断开红蓝联系可以在一定程度激发国产化发展&#xff0c;但是不得…

Oracle OCP证书有效期是三年?

这一段时间&#xff0c;网上经常传出消息Oracle OCM认证证书有效期为三年&#xff0c;其实这个假消息&#xff0c;通过博睿谷与Oracle官方人员确认&#xff0c;OCP认证证书有效期是永久的。 OCP证书本身永久有效&#xff0c;但老版本的OCP证书代表着更多的项目经验&#xff0c…

Python 闭包:函数式编程中的魔法变量容器

闭包与匿名函数的常见混淆 在编程社区中&#xff0c;闭包(closure)和匿名函数(anonymous function)经常被混为一谈&#xff0c;这种混淆有其历史根源&#xff1a; 历史发展因素&#xff1a;在早期编程实践中&#xff0c;在函数内部定义函数并不常见&#xff0c;直到匿名函数广…

迅睿CMS导入别站数据库

<?php if (isset($_GET[go])) {$host localhost;// 数据库服务器$username uname;// 数据库用户名$password pwd;// 数据库密码$database database;// 数据库名$cmscid $_GET[cmscid];$mtabcid $_GET[mtabcid];if ($_GET[go] step1) {//第一步&#xff1a;先获取CMS…

基于C++、JsonCpp、Muduo库实现的分布式RPC通信框架

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;项目 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 项目介绍JsonCpp库简单介绍Muduo库简单介绍C11异步操作——std::future1. 使用 std::async 关联异步任务2. std::packaged_task 配…

EPSG:3857 和 EPSG:4326 的区别

EPSG:3857 和 EPSG:4326 是两种常用的空间参考系统&#xff0c;主要区别在于坐标表示方式和应用场景。以下是它们的核心差异&#xff1a; 1. 坐标系类型 EPSG:4326&#xff08;WGS84&#xff09; 地理坐标系&#xff08;Geographic Coordinate System&#xff09;&#xff0c;基…

Docker 使用与部署(超详细)

目录 引入 入门使用 部署对比 镜像仓库 命令解释 基础 常见命令 示例 数据卷的使用 数据卷的概念 数据卷的使用 挂载本地目录文件 镜像 结构 Dockerfile 容器网络 部署 DockerCompose 语法 ​编辑 基础命令 引入 当我们在 Linux 上部署一个集成了很多中间件…