本笔记有特殊目录,点击开启: 专有目录
在Linux系统中编辑文本总是离不开一位老帮手—— Vi。而因为其诞生的年代有些久远,有些操作在现在看来可能有点”反直觉”。
于是我决定写这样一篇小笔记,记录一下我 记忆Vi的这些这些 常用 操作和指令的方法( 主要靠的是英语和图示了)。
当然,正如”好记性不如烂笔头”所言,多实践才是熟练掌握技能的王道。
关于Vi/Vim名词本身
Vi
代表的可能是Visual Instrument(可视工具)
,Visual Interface(可视界面)
亦或就是Visual(可视化的)
单词本身。Vim
倒是很明显,代表的是Vi IMproved(Vi改进版)
。
编辑器模式
对 Vi
而言:
- 命令模式 (
Command
mode) ,刚进入Vi编辑器时的默认模式。在此模式下能输入Vi的合法指令(通常是一些字符)来进行操作。 - 插入(输入)模式 (
Insert
mode) ,顾名思义,是直截了当地编辑文本的模式。 - 末行(底线)模式 (
Last-line
mode) ,也是接受指令的一种模式,更偏向于文件的管理。
之所以叫 “末行” 是因为指令的输入在窗口最下方:
Vim
是 Vi
的增强版,因此 Vim
完全可以兼容 Vi
的操作,不过它的模式名可能略有差别:
- 正常模式 (
Normal
mode) ,是启动Vim
后的默认模式。 - 插入模式 (
Insert
mode) ,这个和Vi
的一致。 - 命令(行)模式 (
Command-line
mode),类似Vi
的末行模式。 - 可视模式 (
Visual
mode) ,和普通模式类似,不同的是可以 高光选择文字的一部分进行命令操作。 包括上述几种模式,Vim总共有12
种模式(这个说法来自Wikipedia)。但 最常用的还是上面这四种,一般情况下够用了。
模式切换
展开阅读
就 Vi
的三种模式而言,要在其间互相切换,需要借默认模式—— 命令模式作为一个中转(对于 Vim
来说就是 正常模式)。
- 命令模式 ; 作为进入
Vi
的默认模式,我们可以把这儿当作一个小家,
无论在哪个模式下 按Esc
(可以记成Escape
[v.]逃离。逃回家了)都可以回到命令模式。(家是永远的港湾啊) 再提一嘴,在Vim
里这个模式称为 正常模式。 - 插入模式 通过以下按键指令能进入插入模式。这些按键通常是 大小写成对的, 小写对应的指令略显 “温和” , 大写对应的就比较 “走极端” 了。
i
/I
插入 (记作Insert [v]插入;嵌入;(在文章中)添加
) ; 小写的i
,就是在 光标所在位置进入插入模式: 大写的I
则有点”极端”,会 跳转到当前光标所在行的开头进入插入模式:a
/A
附加 (记作Append [v]增补,追加
) 小写的a
,就是在 光标所在位置之后一位进入插入模式,即所谓的”附加”: 显而易见,大写的A
就会 跳转到当前光标所在行的末尾进入插入模式(在尾部附加):o
/O
新增一行 (暂且记作Open
new line) ; 都是新增行,差别无非是往下新增还是往上新增了。 小写的o
,就是在光标所在行的 之后新建一行,然后进入插入模式: 大写的O
呢,就比较蛮横,会把光标所在行及其以下的行整体往下顶,在原位置新建一行(相对来说就是 在光标所在行上面新建一行),然后进入插入模式:s
/S
剪切(取代) (可以直接记删的拼音Shan
,也可以记成Substitute [v]取代
) 小写的s
,会 剪切光标所在位置右边的字符,然后进入插入模式: 大写的S
就很暴躁了,会 剪切光标所在行,然后进入插入模式:
记
Substitute
的话,可以理解为这个操作是剪切原有字符/行
后进行插入, 取代原有的字符/行
。 💡S
和cc
指令的功能是相同的!这个在下面的“剪切一行”;这一节中也提到了。 上面这些按键指令都是在命令模式/正常模式
下输入的,通过 在指令前附加数字,能重复这个指令的操作:3s
-> 删除光标后3
个字符4a
-> 在光标下一位附加内容, 操作结束后(Esc)把这个内容重复4
次- 替换模式 ; 这个模式和插入模式一样是用于编辑文本的,不同的是替换模式下 输入所至之处会覆盖一切。 记作
Replace [v]取代;代替。
输入大写R
进入替换模式: 有了大写R,那么小写r
呢?小写r的功能是 将光标后面的字符替换为指定字符。比如我们先输入r
,再输入a
: 当然,这些操作一样是可以重复进行的: (指令分别是3rp
,3R
->hello
->Esc
) - 末行模式(Vim中的命令行模式) 输入
Shift
+:
进入末行模式(事实上我们一般都是这样打出冒号来的) 末行模式在Vim
中被称为 命令(行)模式。 - 可视模式 可视模式是
Vim
中新引入的模式,支持在高光选择下进行指令操作。 可视模式即Visual Mode
,进入可视模式的按键则是v
/V
, 其中v
键能普通地进入可视模式: 而V
在进入可视模式后 会保持高光选择到光标所在行( 可视行模式): 还有一种便是使用Ctrl+V/v
进入可视模式了,这种模式叫 可视块模式,如字面所言,是选择”一块文字”:
命令模式/正常模式
这是进入 Vi/Vim
后所处的默认模式,和文本处理是靠的非常近的,我决定先记一下这部分。
- 模式切换
- 基本光标移动(上下左右) 在交互式字符界面下没有能动的鼠标,只有闪烁的光标来标注位置。要编辑文本,真得先掌握移动光标的指令。 PS: 下方涉及的光标 上下移动都是 针对换行符
\n
分隔的行的,光标会从一行移动到上方或下方的行:展开查看示例 👆j
、k
、↓
、↑
将光标从一行的指定位置移动到另一行的 指定位置。 👆Enter
、-
,将光标移动到下一行或上一行的 行首! - “经典”款 ;
h
向左移动光标
l
向右移动光标
k
向上移动光标
j
向下移动光标 之所以这样设计,因为在早期 终端机上,键盘是这个样的: 记忆方法:现代键盘上↓
、↑
键在中间,而←
、→
键在两侧,而HJKL也正是两侧的K
、L
代表横向移动,中间的J
、K
代表纵向移动(HJKL四个键连在一起的设计一直保留到了今天)。 - 现代款
←
向左移动光标
→
向右移动光标
↑
向上移动光标
↓
向下移动光标 - “隐藏”款
Backspace(退格键)
向左移动光标
Space(空格键)
向右移动光标
👆记忆方法:在插入模式下,
Backspace
和Space
是分别用于删去字符和增加空格的,与之对应的光标分别是 往左移动和 往右移动的。Enter
把光标移动到 下一行行首
+
把光标移动到 下一行行首
-
把光标移动到 上一行行首
👆记忆方法:插入模式下Enter
起到了换行作用,换行后光标会处于行首。
-
就记成”减去一行”(老实说我也不太知道这个怎么记了,JK其实也够用了),
+
和-
记在一起就行。 PS: 光标移动是在命令模式/正常模式
下的指令,当然是支持重复的啦! 在上面所有指令的前面加上重复的次数(数字)即可,比如我要往下翻233
行:233j
或233↓
。 - 行内光标移动 这里记录一下在 一行文本中光标的移动指令:
- 跳到行首
0
回到行首,列数
=1
的地方
Home
同上👆
^
回到行首, 第一个不为空白符的字符处(对于加了缩进的行可谓是非常有用)
👆记忆方法:
0
记为”归零”;
^
的话, 正则表达式里是用于匹配字符串首部的,可以一起记,另外其还形如一个顶部,可以记成一行中的”顶头”部分。 - 跳到行尾
$
回到行尾 最后一个字符的地方
End
同上👆
g_
回到行尾 最后一个不为空白符的字符处
👆记忆方法:
$
在正则表达式里是用于匹配字符串尾部的,可以和正则表达式一起记;
g_
可以记成go _
,_
形如一个输入光标,这样记成跳转到行尾最后一个非空白字符。 - 屏幕可见行中移动光标 上面所说的”行”取决于 换行符
\n
的位置,但这里的 屏幕可见行是取决于窗口大小的: (图中标注的即为 一个屏幕可见行) ; 针对这样的一个行,也是有指令可用于行内移动的: g^
跳转到行首第一个不是空白符的字符处
👆记忆方法:
g^
可以记成go ^
,去往当前的顶头部分。g0
跳转到行首字符处gm
跳转到 行中间的字符处
👆记忆方法:
gm
可以记成go midst
,去往当前的中间部分。g$
跳转到行尾字符处 完全是可以结合前面的0
,^
,$
一起记的。当然,g + Home
,g + End
也是可以的。 再展开想想,既然g
开头的指令 在这里看的是屏幕可见行,我是不是可以用gj
(或g↓
)指令从一个屏幕中的行移动到另一个行呢? 👆这个主要是用j
(↓
)指令进行的光标移动 👆而这个主要是用gj
(g↓
)指令进行的光标移动。
利用
g
+移动指令
,可以实现在屏幕中的行之间移动。当然,3gj
这种移动多行的指令也是支持的哦~ 针对屏幕可见行,还有几个指令:- 大写
H
用于将光标移动到 屏幕可见的 最上面一行(这个判定有点怪,可能不太准确!)
👆记忆方法:
H
可以记成Head
,去往可见区的头部。 - 大写
M
用于将光标移动到 屏幕可见的 最中间行(同样判定很怪)
👆记忆方法:
M
可以记成Middle
,去往可见区的中间部分。 - 大写
L
用于将光标移动到 屏幕可见的 最下面一行
👆记忆方法:
L
可以记成Last
,去往可见区的最后一行。 - 文件内光标移动 除了上述几种移动外,还有几个常用指令能按词、按句、按段等移动光标:
- 按词移动
w
跳转到 下一个词的开头部分( 考虑标点符号),演示如下👇W
跳转到 下一个词的开头部分(只考虑 空格分隔) ,演示如下👇b
跳转到 上一个词的开头部分( 考虑标点符号)。B
跳转到 上一个词的开头部分(只考虑 空格分隔)。 这里的b
、B
和w
、W
的操作就是 反着来的。
👆记忆方法:
w
可以记成word next
,下一个单词;
b
则记成behind word
,后一个单词。
W
和B
则比较”激进”,不会考虑标点符号。 ;e
跳转到当前 光标所在词的 词尾,如果光标在词尾,就跳转到 下一个词的词尾 ( 考虑标点符号)。E
同上👆,但是 只考虑空格分隔。
👆记忆方法:e
可以记成end of word
,词尾。 - 按句移动
(
移动到 光标所在句子的开头部分,如果已经在开头,就移动到 上一个句子的开头部分)
移动到 下一个句子的开头部分
👆记忆方法:写代码的时候会用半角括号
()
把表达式括起来,可以理解为”一句”。 - 按段落移动
{
移动到 光标所在段落的开头部分,如果已经在开头,就移动到 上一个段落的开头部分}
移动到 下一个段落的开头部分
👆记忆方法:写代码的时候会用半角大括号
{}
把代码块括起来,也就成为了一”段”代码,可以理解为一个段落。 值得注意的是,上面这些按词、句、段落移动光标的操作,主要是 针对英文句式的。如果操作对象是中文的话,可能并不能如愿。
(最明显的就是按词移动W
,中文里一般是不会用空格分隔每个词的,所以会直接跳转到一段的末尾!) - 在整个文件中跳转光标 ⚠️ 下面的指令全部都会使光标 跳转到行首第一个不为空白符的字符处。
gg
跳转到文件 最开头的一行,相当于1G
。G
跳转到文件 最末尾的一行。[row]G
跳转到文件 第[row]行(row代表数字)。 👆 分别演示了gg
,G
,2G
的操作。
记忆方法:上面三个指令本质都和
G
有关,G
可以直接记忆为Goto 转到,跳转
。 - 自定义跳转标记 ; 在这一坨文本中进行移动时,我经常要使用指令反复横跳。有一个地方我 经常跳转过去,如果一步步来实在很麻烦!此时就可以用 自定义跳转标记来解决。
- 设置标记 指令非常简单:
ma
这样就设置了一个名为a
的标记! 经过测试发现m
后面可以接a-zA-Z0-9
之中的任意字符!
也就是说
m1
,mA
,mO
,mz
这些都是合法的指令!
👆记忆方法:m
可以直接记忆为Mark [v]标示,标记
。 - 跳转到标记处
等等其实都是可以的!a</code> 这样就能跳转到 <code>a</code>标记处~ 标记名是 <strong>大小写敏感的</strong>。<blockquote> <p>💡 可以和下面的 <code>y</code>, <code>c</code>, <code>d</code>指令联合使用。</p> </blockquote> </li> <li><strong>跳转到标记所在行的行首</strong> <code>'a</code> 使用单引号 <code>'</code> 加标记名能跳转到 <strong>该标记所在行</strong>的行首 <strong>第一个不为空白符的</strong>字符处! <img alt="" src="https://assets.xbottle.top/img/jump2markedLine-2022-04-12.gif" /><blockquote> <p>这样是不是就相当于标记了一个行的行首呢?</p> </blockquote> </li> <li><strong>删除标记</strong> <a name="normalmode-makemarks-del">;</a> ma可以设置名为 <code>a</code>的标记,删除的话其实在前面加个del即可: <code>delm a</code> 或 <code>delmarks a</code> ( <code>Delete Marks</code> ) 同时支持 <strong>删除多个标记</strong>。比如我要删除 <code>a</code>, <code>b</code>, <code>c</code>三个标记,可以写成: <code>delm abc</code> 或 <code>delmarks a b c</code> 也就是说删除标记的时候 <strong>标记名之间有没有间隔是无所谓的</strong>。<blockquote> <p>💡 在进行了<a href="#indenting"><strong>缩进操作</strong></a>后,标记的位置仍然在文本的相应位置,无需担心。 <code>末行模式/命令行模式</code>下可以 <strong>查看标记信息</strong>:<a href="#commandlinemode-viewmarks">:marks</a></p> </blockquote> </li> <li><strong>翻页</strong></li> <li><strong>后空翻</strong> <code>Ctrl + b</code> 往回翻 <strong>一整页</strong><br> <code>PageUp</code> 往回翻 <strong>一整页</strong><br> <code>Ctrl + u</code> 往回翻 <strong>半页</strong><blockquote> <p><strong>👆记忆方法</strong>: <code>b</code> 代表 <code>Backward</code>,也就是往回;<br> <code>u</code>则代表 <code>Up</code>,也就是往上(在界面上往回翻就如同往上翻);<br> <code>PageUp</code>不多赘述,在现在的大多系统中都是支持的。</p> </blockquote> </li> <li><strong>前空翻</strong> <code>Ctrl + f</code> 往前翻 <strong>一整页</strong><br> <code>PageDown</code> 往前翻 <strong>一整页</strong><br> <code>Ctrl + d</code> 往前翻 <strong>半页</strong><blockquote> <p><strong>👆记忆方法</strong>: <code>f</code> 代表 <code>Forward</code>,也就是往前;<br> <code>d</code>则代表 <code>Down</code>,也就是往下(在界面上往前翻就如同往下翻)。 <code>Ctrl</code>键代表 <code>Control</code>,在这里可以理解为 <strong>控制</strong>页面滚动。 <strong>PS:</strong> 再记忆一下, <code>命令模式/正常模式</code>下的指令是可以重复的。在这里如果我要向前翻 <code>3</code>整页: <code>3PageDown</code>或 <code>3Ctrl+f</code>。</p> </blockquote> </li> <li><strong>复制</strong> 复制是文本的经典便捷操作之一。</li> <li><strong>复制一行</strong> <code>yy</code> 复制光标所在行(到寄存器中)<br> <code>Y</code> 同上<blockquote> <p><strong>👆记忆方法</strong>: <code>yy</code> 中的 <code>y</code>代表 <code>yank [v]猛拉;猛拽</code>,复制其实就是把对应的文本给"拽走"了。</p> </blockquote> </li> <li><strong>多行复制</strong> <code>2yy</code> 复制 <strong>光标所在行</strong>以及 <strong>下一行</strong>,共 <code>2</code>行<br> <code>2Y</code> 同上<br> <code>10yy</code> 复制 <strong>光标所在行</strong>以及 <strong>下面9行</strong>,共 <code>10</code>行<blockquote> <p>本质上其实就是 <code>命令模式/正常模式</code>下的指令重复(在指令前面加数字前缀)。</p> </blockquote> </li> <li><strong>打一套复制组合拳!(选区复制)</strong> <code>y</code>其实可以和很多 <strong>光标移动指令</strong>结合使用!利用好这套"组合拳",效率倍增有木有! <img alt="" src="https://assets.xbottle.top/img/yankBoxing-2022-04-10.png" /> 比如 <code>ye</code> 就能复制光标所在位置到<a href="#normalmode-moveinfile-endofword"><strong>单词尾部</strong>;</a>的部分, 而 <code>y^</code> 能复制光标所在位置<a href="#normalmode-moveinsiderow-jumpaheadofline"><strong>到行首</strong></a>第一个非空白符的单词部分, 再者 <code>y↓</code> 或 <code>yj</code> 能实现同 <code>2yy</code>一样的功能: <strong>复制光标所在行</strong>以及<a href="#normalmode-arrowmovement"><strong>下一行</strong></a>, 甚至 <code>y(</code> 都是可以的,复制 <strong>光标所在位置</strong>到<a href="#normalmode-moveinfile-moveaheadsentence"><strong>光标所在句开头</strong></a>。<blockquote> <p>也就是说 <code>y{</code>, <code>y}</code>, <code>yk</code> , <code>yl</code> , <code>y$</code> , <code>yg^</code>, <code>y
另外还可以复制多行,比如3ygj
。 🤩 总结一下就是:y
可以和很多 光标移动指令结合使用达成 部分复制的效果, 通常以 光标所在位置为起点,直到 光标移动指令执行后的光标位置为止作为 选区进行复制。 👆示例ygj
的效果。光标所在位置是语
字前面,执行gj
后光标位于草
字前面,所以复制选区就是:语人曰:“此当有大手笔事。”俄而帝崩,哀册说议皆淘所
。 - 剪切 ; 有了复制,就不得不提到 复制并移除——剪切了。通过这些指令移除的文本会被存进寄存器,可用于 粘贴。
- 剪切一行
dd
剪切 光标所在行
cc
剪切 光标所在行,并且 进入插入模式
S
同上👆,这个其实在模式切换这一节里面写了
👆记忆方法:
dd
中的d
记为delete [v]删除
;
cc
中的c
记为change[v]改变
,亦可记成Chi 吃
;
S
可以记成Shift [v]转移
,剪切就像是在转移文本的位置,亦可记成Shan 删
。 - 剪切多行 这一部分和复制多行真的相差无几,可以说会用多行复制了,肯定是会剪切多行的。
2dd
剪切 光标所在行和 下面一行,共2
行
6dd
剪切 光标所在行及 下面5行,共6
行
3cc
剪切光标所在行及下面2行,并进入 插入模式
3S
同上👆 - 剪切一个字符
x
剪切 光标右边的一个字符 (相当于dl
或d→
)
s
剪切 光标右边的一个字符,并且 进入插入模式
👆记忆方法:
x
中的x
记为画个叉叉删掉字符
;
s
则可以记为shan 删
。 - 行内剪切 和复制不同的是,大写
D
和C
的作用 并不等同于dd
和cc
!D
剪切从 光标所在位置到 光标所在行的行末部分
C
完成上述操作👆,并且进入 插入模式
C
相对D
仍然是多出了个 进入插入模式的功能 - 组合剪切(选区剪切) 复制
y
能打组合拳,我堂堂剪切为什么不行! 确实,剪切d
或c
都是可以和 光标操作指令进行结合的,
他俩不同的地方在于d
只是普通的剪切,c
还附赠了切换到插入模式服务!dj
或d↓
的效果就等同于2dd
cj
或c↓
的效果就等同于2cc
,会进入插入模式
5x
能剪切光标右边的5个字符
5s
能剪切光标右边5个字符且进入插入模式
3cgj
能剪切从 当前光标到3
个 屏幕可见行后的相应位置部分
dw
剪切从 当前光标位置到 下一个单词前的部分
cw
在进行上面的操作👆后,会进入 插入模式
d^
剪切从 当前光标位置到 本行头部一个不是空白符的字符的部分
c^
在进行上面的操作👆后,会进入 插入模式
d`a
剪切从 当前光标位置到a
标记位置;的部分 👆演示了一下3dgj
。从光标所在位置语
开始,到执行了3gj
之后的光标位置 为止作为选区,进行剪切。也就是这一部分:
语人曰:“此当有大手
笔事。”俄而帝崩,哀册说议皆淘所草。释义用来赞誉写作才
能极高,并用来称颂着名的作家和作品、故事东晋的文士王玖
从小才思敏捷,胆量很大,散文和诗
🤩 总结一下就是: d
/ c
可以和很多 光标移动指令结合使用达成 部分剪切的效果, 通常以 光标所在位置为起点,直到 光标移动指令执行后的光标位置为止作为 选区进行剪切。
💡 应该和 复制结合记忆!
10. 粘贴 Copy和Cut都记了,接下来咱要想办法粘贴(Paste)内容咯~ 粘贴的指令其实非常简单!( ´・ω・)ノ
–p
(向下一行/向右)粘贴文本一次(记为Paste [v]粘贴
)
– 大写P
(向上一行/向左)粘贴文本一次(记为Upper(大写,同时也有“上边”的意思) Paste
) 当 寄存器中的内容是 一行或多行文本(开头有换行符\n
)时:
–p
会把文本粘贴到当前 光标所在行的 下一行,
– 大写P
会把文本粘贴到当前 光标所在行的 上一行!
– 👇举例:先利用yy
复制 一行文本,然后分别用p
和P
进行粘贴
很明显能看到使用p
时,该行文本会被粘贴到line2
这一行的下方;
而使用P
时,该行文本会被粘贴到line2
这一行的上方。 ; 当 寄存器中的内容是 不足一行的文本( 开头没有换行符\n
)时:
–p
会把文本粘贴到当前 光标所指字符的 右边,
– 大写P
会把文本粘贴到当前 光标所指字符的 左边!
– 👇举例:先执行ygj
复制 开头没有换行符的一段文本,然后分别用p
和P
进行粘贴
粘贴的时候 光标指向的字符是n
。使用p
粘贴时,内容粘贴在n
的右方;而使用P
粘贴时,内容粘贴在n
的左方。 🌟命令模式/正常模式
下指令可加数字前缀重复执行,这里也是一样的。比如4p
就是把寄存器的文本在光标右边/下一行 粘贴四次。
11. Vim上下文编辑 Vim在复制y
,剪切c
、d
这些操作的基础上复用了i
和a
指令用于对上下文进行操作:
👆记忆方法:i
记作inner 内部的
,在下面使用这个指令,操作 不会考虑周围的空格或符号;
a
记作around 周围
,这个则 会考虑周围的空格或符号。具体视情况而定。
– 针对单词(w
/W
)
⭐ 记作Word
diw
剪切 光标所在的单词(不考虑标点符号)diW
剪切 光标所在的单词(考虑周围的标点符号,也就是说剪切的时候会把周围的标点符号一并算进去)i
(inner) 在这里的意思是操作的部分 不包括单词周围的空格daw
和daW
也是剪切 光标所在的单词(w
和W
区别不再多赘述)a
(around) 在这里的意思是操作的部分 包括单词周围的空格 ※ 下面演示一下diw
和daw
的区别: 很明显能看到,使用diw
时,剪切后遗留的文本是of ,
(单词左边的空格保留了);
使用daw
时,剪切后遗留的文本是of,
(单词左边的空格被一同剪切了) 。
💡 像y
,c
,d
一类指令都是可以这样用的,比如yaw
,yiW
,ciw
,caW
等等…
- 针对句子(
s
) ;
⭐ 记作
Sentence
。注意,这里 没有大写S
的用法! 其上下文操作和上面单词的是一样的!比如:yis
复制 光标所在的句子(i
不考虑周围的空格)
yas
复制 光标所在的句子(a
考虑周围的空格)
cas
剪切 光标所在的句子,并进入插入模式
dis
剪切 光标所在的句子
…and so on
💡 注意,这里只有小写s
的用法。 - 针对段落(
p
)
⭐ 记作
Paragraph
。注意,这里 没有大写P
的用法! 这里的用法也和上面是一样的:cap
剪切 光标所在的段落,并进入插入模式(a
考虑周围的空格)
dip
剪切 光标所在的段落(i
不考虑周围的空格)
yip
复制 光标所在的段落
…and so on
💡 这里同样只有小写p
的用法。 - 针对单/双引号(
'
/"
) 很明显,这一部分操作是用来处理单/双引号 引起来的文本的,和上面的w
、W
、s
、p
不同的是这里的i
/a
的含义:
i
(inner) 在这里的意思是操作的部分 不包括两侧的引号
a
(around) 在这里的意思是操作的部分 包括两侧的引号di"
剪切光标所在的 双引号引起来的 同行文本(i
代表不包括两侧的引号) 👇da'
剪切光标所在的 单引号引起来的 同行文本(a
代表包括两侧的引号) 👇
💡y
和c
也是一样的用法 - 针对括号 (
( )
,< >
,[ ]
,{ }
) ; 这一部分用来处理 括号括起来的文本。
📌 注意, 这里的操作是支持多行的!!
i
(inner) 在这里的意思是操作的部分 不包括两侧的括号
a
(around) 在这里的意思是操作的部分 包括两侧的括号di(
或di)
剪切光标所在的 小括号( )
括起来的文本(i
代表不包括两侧的括号) 👇da{
或da}
剪切光标所在的 大括号{ }
括起来的文本(a
代表包括两侧的括号) 👇
💡y
和c
也是一样的用法,适用于多种括号。 - 双引号指定寄存器 默认情况下使用复制粘贴似乎用的都是一个公共的寄存器(Registers),Vim实际上是支持寄存多条文本的, 只需要在指令前指定寄存器名即可。
- 默认的寄存器被系统记为
"
,一个双引号 当执行yy
时,会将目标文本行存入"
寄存器,操作等同于:""yy
💡 其中第一个单引号代表 引用寄存器,第二个单引号便是 默认寄存器的名字。 于是粘贴指令也可以改写成:
""p
,即从默认寄存器中取出文本进行粘贴。 - 指定寄存器名字 把上述第二个单引号改成
a-z
的 小写字母即可!这样就相当于得到了26
个”剪贴板”呢~ 比如将当前行复制到a
寄存器中:"ayy
那么粘贴该内容的指令也显而易见了:"ap
- 往已命名寄存器中附加内容 上面写到用 小写字母对寄存器进行命名,那么 大写字母呢? 大写字母用于往寄存器中 附加内容:
"Ay$
将光标位置到行尾的文本附加到a
寄存器中 👇 这里主要记录一下复制粘贴方面的寄存器引用方法。Vim寄存器储存的内容远不止这么一点,还包括操作历史记录等信息,就不多赘述了。
👆记忆方法:
"
就像个图钉📌,标明是哪一个寄存器。末行模式/命令行模式
下可以 查看寄存器信息::reg[isters] - 缩进 ; Vi/Vim 常用于编辑代码,缩进功能当然也是比较常用的了。
- 增加缩进
>>
给 光标所在行增加缩进
4>>
给 光标所在行以及下面3
行增加缩进,共4
行 - 减少缩进
<<
给 光标所在行减少缩进
5<<
给 光标所在行以及下面4
行减少缩进,共5
行
👆记忆方法:
>
可以看作在往右边”顶”文本,而<
可以看作在往左边”拉”文本。 - 撤销与重做 文本编辑必不可少的便是撤销与重做功能了!
- 撤销
u
撤销 上一步操作 大写U
撤销 光标所在行的 所有操作
👆记忆方法:
u
直接记成undo [v]撤销,取消
即可。
一定要辨别小写u
和大写U
的操作区别! - 重做
Ctrl + r
或者Ctrl + R
重做操作和小写u
的操作是反向的!重新执行撤销掉的操作。
👆记忆方法:
r
直接记成redo [v]重做
即可。
为什么多了个Ctrl
呢?因为r
已经被 替换模式占用了! - 数字快捷增减 要修改一个数值的时候可以进入插入模式,移动光标到数值上进行修改,这样可能略嫌麻烦了。在
命令模式/普通模式
下提供了对 数值进行 递增或 递减的操作指令: Ctrl + a
(Ctrl + A
亦可) 对光标指针所在数值进行 递增操作。如果光标没有指向数值,会 向右查找数值进行递增。
💡 记忆方法:
👆 示例中可以看到,当光标右方没有数值时会屏幕闪烁提示指令无效。a
可以记成ascend [v]上升;升高;递增
,
亦可以记成accumulate [v]积累;逐渐增加
。
之所以有Ctrl
,是因为a
已经被用于切换 插入模式了!Ctrl + x
(Ctrl + X
亦可) ; 对光标指针所在数值进行 递减操作。如果光标没有指向数值,同样会 向右查找数值进行递减。
💡 记忆方法:
x
可以记成叉掉数字,从而让数值减小
。
之所以有Ctrl
也是因为x
已经被用于 剪切字符。- 重复指令 设想一下,如果我要增加10亿,难不成要一直按住按键不动?当然不是这样啦! 再记忆一遍,
命令模式/普通模式
下的指令可以加 数字前缀进行重复,在这里只需要这样输入指令即可快速递增指定数值:1000000000Ctrl + a
Ctrl + x
同理! - 进制的表示方法 ;
0x
前缀表示 十六进制 (记 hex的 x)0
前缀表示 八进制 (记 octal的 o,虽然这里是 0)0b
或0B
前缀表示 二进制
💡 Vim支持 进行增减的类型有:二进制数( binary),八进制数( octal),十进制数(decimal,默认支持),十六进制数( hexadecimal),无符号数( unsigned),字母( alphabetical)。类型
nrformats
中的表示 二进制binarybin
八进制octaloctal
十六进制hexadecimalhex
无符号数unsignedunsigned
字母alphabeticalalpha
👆 具体配置见末行模式/命令(行)模式
的nrformats配置一节。 - 字母大小写切换 数字增减有了,字母其实也是可以”随地大小变”的!
gu后接光标移动指令
将从光标位置开始到 执行移动指令后光标的位置结束作为选区,
将选区内的所有字母转换为 小写! 👆 演示了guiw
指令。iw
选择的是光标所在单词FLOOD
,执行gu
后将单词所有字母转换为 小写:flood
。gU后接光标移动指令
; 将选区内的所有字母转换为 大写
💡 记忆方法:
gu
和gU
中一个是小写u
,一个是大写U
。大写U
可以记成UPPERCASE 大写
,而当U小写成为u
,对应的便是小写
了。g
仍然可以记成go
,go UPPERCASE
。~
(波浪符) 波浪符将 光标所在的字母进行 大小写交换,比如b
会转换为B
;B
则会转换为b
。 这个指令可以用于转换 光标所在行中 自光标往后的字母 大小写。 👆50~
,将本行中自光标往后50个字符进行大小写转换。g~后接光标移动指令
; 上面的~
只能对 光标所在行的字符进行大小写交换,如果要涉及 一个选区呢? 于是,g~
他来了!在g~
后接光标移动指令,将 光标当前位置开始到 执行指令后光标所在位置为止之间的字符进行大小写交换。 👆g~2gj
,将从光标位置开始到光标向下移动 两个屏幕行为止的部分字符大小写交换。
💡 记忆方法:波浪线可以看作是一条 波,随着波的传播,同一个地方的 波峰波谷交替出现,在这里就记成 大写小写的交替。
- 重复最后一次更改
.
↑ 没错,指令就是一个句点! 比如,之前我输入了3dd
剪切了三行文本,之后再按一次.
会再往下剪切三行; 又比如,我先输入了x
剪切光标所指的字符,之后输入3.
就会再剪切三个字符。 但是!,如果我先输入3j
让光标往下移动3行,再按.
是没有效果的,因为j
指令仅仅是移动了光标, 没有对文本造成任何更改!
⚠ 注意!
.
重复的是 最后一次更改,而不是最后一次指令!
👆 记忆方法:硬背 - 行连接指令
- 大写
J
这个指令能将 光标所在行和其下面一行 连接成一行,之间用 一个空格间隔:
4J
的话则是将光标所在行和 下面3行进行连接,每行之间用空格隔开。 一共4行。
💡 记忆方法:直接记Join [v]加入;连接
即可。 gJ
; 同样是连接行。和上面J
不同的是,这个指令在连接行之后 不会在之间添加空格!。
💡 记忆方法:可以记成
gross Join
,gross
有总的;粗鲁的
的意思,gross Join就可以记成 ” 连接成一个总体” 或者 ” 粗鲁地直接连在一起“。
末行模式/命令(行)模式
在这种模式下,涉及到最基本的操作,如保存/退出编辑器。
[En]
The most basic operations such as saving / exiting the editor are involved in this mode.
:w
写入 (记为Write [v]写文件
) 顾名思义,这个指令会将 自开始编辑以来的更改写入文件中: ; 文件保存总让人想起桌面软件的”另存为”功能,当然Vi
也是能实现的: ⭐:w filename
除了上面针对单一文件的写入指令,还可以同时 写入多个文件,下面这个指令适用于Vim编辑器中同时打开多个文件的情况: ⭐:wa
👆 将所有打开的文件进行写入保存。(可以记成Write All 写入所有
) ; 如果只想保存文本中的一部分呢?Vim还支持指定行写入文件: ⭐:<line1>,<line2> w filename</line2></line1>
👇 比如我想写入第13
至第14
行的文本(共两行)::13,14 w filename
输出文件效果:-
:q
退出(记为Quit [v]离开;关闭
) 文本编辑器必备操作——关闭文件。 ⭐:q
指令会退出 当前编辑的文件(如果只打开了一个文件,这个操作同时会 退出编辑器) ⭐:qa
指令则会退出 所有打开的文件,并且 退出编辑器。👆 记忆方法:
Quit All 关闭所有
注意:上面这两个指令执行的前提是 当前文件自打开后没有任何更改,也就是说文件缓冲区中没有任何新增内容,不然编辑器会警告文件尚未保存更改。
如何强行退出?它将被写在下面。[En]
How to force an exit? It will be written below.
-
联合使用
既然未保存没法正常关闭文件,那么保存后关闭不就行了嘛! ⭐w
与q
:wq
👆 双剑合璧,数据无忧!这个指令会将缓冲区中的编辑内容 写入文件,并且 关闭文件。(针对 当前正在编辑的文件) 当然,也有针对 编辑器所有打开的文件的操作: ⭐:wqa
👆 写入并关闭 所有打开的文件,这之后会 退出编辑器。(Write & Quit All
) - 感叹号
!
强制执行指令 ; 有些情况下末行模式指令的执行可能会被拒绝,比如上面的:q
在文件保存前不能直接执行。(这一点其实也是为了数据安全) ⭐ 然而,只需要在这些指令 末尾加上感叹号!
就可以 强制执行了! 比如 未保存强制退出编辑器就可以用::qa!
此外我觉得 文件强制写入也是值得记录一下的::w!
👆 这个指令会 尝试强制写入文件,即使文件是只读(Read-only)的,前提是 用户得要有修改文件属性的权限。
⚠ 强制执行指令时一定要再三考虑,防止数据丢失等问题。
:r
在下一行读入文件 (记成Read [v]读取
) 在编辑文本的时候可能需要将 另一个文件的文本插入进来,这个时候就轮到:r
大显身手了。 ⭐:r
能够 读取一个文件,并将文件内容 追加到光标所在行的 后一行。 👆 左边是待读取的文件,右边是正在编辑的文件。利用:r
指令,成功将文件内容插入到光标后一行。:e
开启新buffer或刷新当前buffer (记成Edit [v]编辑
) ; 当编辑文件编辑到一半,想要推翻当前的所有修改,该怎么办呢? 一种方法是使用:q!
,强制退出文件; 另一种方法则是:e!
,强制刷新当前buffer
:- 文件在
Vi/Vim
中未经修改但是在 别的软件中受到了修改时,可以直接使用:e
在编辑器里 刷新(重新载入)文件内容。 - 文件做了修改后,也可以用
:e!
强制 重载文件内容,也就是抛弃文件开启以来的所有修改。 ;
buffer可以理解为文件的一个 缓冲区,文件在编辑器中被编辑实际上也就是临时buffer在被编辑。当写入文件的时候就是把buffer中的内容 写入到原文件中,以达成编辑的效果。 除了刷新当前文件的buffer外,
:e
指令还可以用于 打开新的文件并创建buffer。 :e <filename></filename>
打开文件(如果存在的话),创建buffer 👆 前提:目前在编辑的文件已经保存或者未经修改。:e! <filename></filename>
无论 当前文件是否保存(写入),强制打开新文件:buffers
和:bn
,:bp
以及:b<id></id>
:buffers
列出所有buffer,在这里可以看到buffer的ID(最左边一列)。:b<id></id>
; 既然拿到了buffer的ID,我就可以在buffer之间跳转了,比如::b2
跳转到id为2的buffer
注意:这个操作也要求当前编辑的文件 不能有未保存的修改。
:bn
和:bp
就算不知道buffer的ID,利用这两个指令也能在buffer间互相切换::bn
—> 切换到 下一个buffer:bp
—> 切换到 上一个buffer
注意:这个操作也要求当前编辑的文件 不能有未保存的修改。
💡 记忆方法:bn
即buffer next 下一个buffer
;bp
即buffer previous 上一个buffer
。:help [command]
或:h [command]
查看帮助 就像Linux中的man
指令一样,Vi/Vim的末行模式/命令行模式
也有个:help
指令用来查看编辑器使用帮助。 ⭐ 直接使用:help
时会打开帮助文件,并将光标移动到顶部。 ⭐ 指令形如:help [command]
时,在开启文件后光标会跳转到对应的指令帮助信息。
比如要看寄存器指令的帮助信息:
:help reg
或:help registers
(:h reg
当然也行 ):registers
或:reg
查看寄存器 这一部分可以结合命令模式/正常模式
的双引号指定寄存器一起记。 ⭐ 直接使用:registers
或:reg
时会展示 所有的寄存器 👇 也可以在后面 指定要查询的寄存器名,这些名称可以用空格分开,也可以连在一起写: ⭐ 比如:reg[isters] a b c
或:reg[isters] abc
,可以筛选查询a
,b
,c
寄存器 👇 关于寄存器更多用法这里就不多赘述了~:marks
查看标记信息 ; 这个和上面:reg[isters]
的使用 很类似,所以咱给写一起了。 这一部分可以结合命令模式/正常模式
的自定义跳转标记一起记。 ⭐ 直接使用:marks
能查询到 所有现有的标记 和:registers一样,在后接查询的标记名,能筛选结果: ⭐ 比如:marks a b c
或:marks abc
,可以筛选查询a
,b
,c
标记:set
设置项 这个指令用于设置一些配置项,这里就记几个比较常用的(因为配置项有非常多,全写出来太累赘了)- 开启/关闭行号显示
:set number
或:set nu
可以在行首显示行号 而:set nonumber
或:set nonu
则可以关闭行号显示 此外:set nu!
或:set number!
可以在 开启行号/关闭行号之间互相切换。
👆 记忆方法:直接记
Number [n]号码 [v]标号
- 开启/关闭相对行号显示 ;
:set relativenumber
或:set rnu
可以显示相对行号 而:set nonumber
或:set nonu
则可以关闭相对行号显示 此外:set rnu!
或:set relativenumber!
可以在 开启相对行号/关闭相对行号之间互相切换。 👆 可以看到,相对行号以 光标所在行为第0
行,向上或向下标出相对的行号。 这个特性可以用于 辅助涉及多行的指令,比如y3j
,3k
,2>>
等。
💡 记忆方法:按字面记,即
Relative Number 相对 号码
- 识别数字进制的配置 上面已经写过
Ctrl+x
和Ctrl+a
能快捷减增数字。不过呢,Vim怎么识别 增减的类型呢? 这就涉及到下面这个配置项了::set nrformats
或:set nf
直接输入这个指令会查询 该配置项当前的设置: 上面也写过Vim 能识别的增减类型。这里的octal,hex
则代表会尝试识别 八进制, 十六进制以及 十进制的数字。(十进制是默认支持的)- 使用
+=
或-=
进行配置 ; 这种写法其实可以理解为一些编程语言中的 运算赋值操作::set nrformats+=bin
:set nrformats+=bin,alpha
(或者set nf+= ...
) 👆 多个可以用 逗号分隔,会”附加”到配置项的末尾。 然而,移除的时候就要注意了,一定要按 配置中的顺序来::set nrformats-=bin
:set nrformats-=bin,alpha
👆 这样写的话必须保证配置项中也有 bin,alpha这个字串! ↑ 没有bin,alpha
这个字串,无法移除。 ↑ 移除octal,alpha
的话就很成功,因为配置项中有这个字串。 - 直接使用
=
进行配置 同样可以按编程语言里的 赋值来理解,会直接 改变整个配置:set nrformats=octal,hex
👆 多个值一样是用 逗号分隔
💡 记忆方法:
nrformats
可以看成number recognizing formats
,也就是数字识别格式
。取n
和f
即为nf
,因此nf
也可以简单记为number format
!
- 执行Shell指令 编辑文本到一半突然想执行一个Shell指令。我之前可能会利用
:wq
先退出编辑器,输入执行指令后再重新打开编辑器。 实际上在末行模式/命令行模式
下Vi/Vim也是能快捷切换到Shell执行指令的: :! <command>
暂时离开编辑界面,在Shell下执行指令 并打印结果 👆 临时跳转到命令行执行清屏
及查询日期
指令并展示结果。
💡
👆 演示:!
还有很多神奇的用法,比如执行指令后将返回的结果插入下一行::r! <command>
;
又比如将文本21
至25
行进行升序排序,并替换原文本::21,25! sort
,这里就很像Shell中管道符
的用法了。:21,25! sort
更多用法在这里就不多赘述了╮(╯3╰)╭:sh
创建一个新的Shell会话 ; 这个指令就比较简单粗暴了,在执行后会创建一个新的Shell会话,我可以直接在Shell中执行指令! 这个Shell是一个 非登入Shell,所以需要使用exit
指令退出。 该Shell退出后会 回到编辑器界面!
👆 这个直接记忆
Shell
就行- 重复上一条指令 在
命令模式/正常模式
下我可以使用.
句点来重复上一次更改。在末行模式/命令行模式
下也有类似的方法。 - 经典方法 在
末行模式/命令行模式
下输入:
后会进入末行模式/命令行模式
,此时可以通过: ⭐↑
,↓
,PageUp
,PageDown
来浏览之前的输入历史 💡 可以在:
后面输入一些字符以 加快检索: 👆 输入:s
后,能快速浏览:s
开头的历史指令记录;:se
则能快速浏览:se
开头的历史指令。 -
@:
方法 ; 在命令模式/正常模式
下输入:@:
能重新执行 上一条末行模式/命令行模式
指令。
👆 记忆方法:把
👆 演示:先用:
末行指令给 at出来! 虽然我把这个方法写在末行模式这里了,但实际上其可以算是命令模式/正常模式
的指令。 因此也是 可以重复执行的!:d
删除一行,然后再用3@:
重复执行:d
三次以继续删除下面三行。 有点累了…喝口水…
基本搜索替换
- 搜索 前提:在
命令模式/正常模式
下:/<搜索模式><!--搜索模式-->
自光标 向后查找?<搜索模式><!--搜索模式-->
自光标 向前查找
👆 其实
末行模式/命令行模式
下也不是不行,也就多了个冒号::/<搜索模式><!--搜索模式-->
、:?<搜索模式><!--搜索模式-->
。不过接下来这两个指令就不行了 ↓n
—> 这个指令 会重复上一次搜索动作。 - 比如
/....
是往 光标后搜索,按下n
就是 在光标后再次搜索 - 而
?....
是往 光标前搜索,那么按下n
就是 在光标前再次搜索N
—> 这个指令和n
的操作相反
👆 记忆方法:
n
可以记成next [a]下一个的
,正如o和O操作相反一样,N
和n
操作相反。 这里的搜索模式
实际上就是 正则表达式,不过和普通的正则略微有些不同! - 当然是可以直接搜索字串的
- 大小写不敏感搜索 ; 一般在写正则表达式时要进行大小写不敏感匹配我一般会在正则表达式末尾加上
i
标记,但是在搜索模式
里是不行的,需要用到特殊转义标记:\c
这个标记写在搜索模式
的中间(不要写在中括号[]
里!)一般也是可以的,但我觉着还是 放在末尾好辨别一些。
👆 记忆方法:这里的
\c
可以记成case [n]大小写
。 - 利用 正则表达式进行搜索 这里使用正则表达式和在编程语言里有些小区别,这里简单写一下:
- 采用
<
和>
分别匹配 单词词首和 单词词尾,而不是\b
。 - 部分元字符 要发挥元字符的作用的话,需要 先转义。这里列个表格:元字符 用途 在搜索模式中的用法
+
匹配1次或多次\+
?
匹配0或1次(非贪婪模式在Vim中另有元字符)\?
{n,m}
匹配n到m次\{n,m}
{n,}
匹配n次或更多次\{n,}
{n}
匹配n次\{n}
{,m}
匹配0到m次\{,m}
<
匹配单词首部\<
>
匹配单词尾部\>
(
子模式(捕获组)开始标志\(
)
子模式(捕获组)结束标志\)
|
两项之间任意匹配一个\|
%
用于修饰 非捕获组\%
@<=< code>, <code>@<!</code>, <code>@=</code>, <code>@!</code> 向后预查,向前预查 <code>\@<=< code>, <code>\@<!</code>, <code>\@=</code>, <code>\@!</code><blockquote><span> 💡 这种情况是基于Vim<strong>默认设置</strong>的<code>magic</code>模式的,其他模式不多赘述。<br>默认情况下这些元字符如果不转义,就代表<strong>匹配这个字符本身</strong>。</span></blockquote><span> 除此之外的元字符大多是可以直接使用的,下面是一些示例:</span><span> <img src="https://assets.xbottle.top/img/regexSearch1-2022-04-21.jpg"> <img src="https://assets.xbottle.top/img/regexSearch2-2022-04-21.jpg"> <img src="https://assets.xbottle.top/img/regexSearch3-2022-04-21.png"> <img src="https://assets.xbottle.top/img/regexSearch4-2022-04-21.jpg"> <img src="https://assets.xbottle.top/img/regexSearch5-2022-04-21.jpg"></span><span> 另外也是支持<strong>引用子模式的匹配结果(分组)</strong>的:</span><span> <img src="https://assets.xbottle.top/img/regexSearch6-2022-04-22.jpg"></span></code><!--=<--></code></code><!--=<-->
- 采用
- 神奇的 非贪婪模式 ; Vim这里的非贪婪模式用的就不是元字符
?
了,取而代之借用了一下大括号{...,...}
官方说明可以在
末行模式/命令行模式
下输入:help non-greedy
查看。 当{
后面 紧接了一个连字符(Hyphen)-
时,就相当于采用了 非贪婪匹配,下面举些例子:e\{2,3}
匹配ee
或eee
,如果有更长的eee
就优先匹配(也就是 贪婪匹配)e\{-2,3}
匹配ee
或eee
,优先匹配更短的ee
(也就是 非贪婪匹配)
👆 这个例子中在{
后紧接-
后会往少的匹配,也就是只匹配一个paprika
。 如果在-
后面 没有指定匹配次数,就有点类似*
了。形如:\{-}
匹配0-任意
次,但是非贪婪匹配,匹配次数尽量少。\{-,3}
匹配0-3
次,但是非贪婪匹配,匹配次数尽量少。
例:用模式ke\{-}
匹配字串keep
只匹配到了k
,因为\{-}
代表匹配0-任意次
,但是 非贪婪匹配,所以这里e
匹配了0
次。 - 非捕获组与向前/向后预查 在编程语言使用的正则表达式中,非捕获组一般用
(?:模式)
来表示,这一个子模式不会参与分组。 然鹅在Vi/Vim
搜索模式中,非捕获组用的是:\%(子模式\)
(\%\(子模式\)
也行) 来表示的。下面就是一个示例:
可以看到
accept
并未参与分组,\1
引用的是第二个子模式的匹配结果after
接着,在编程语言中的向后/向前预查(?<=)< code>, <code>(?=)</code>, <code>(?<!)</code>, <code>(?!)</code> 在Vi/Vim中也是有特殊的表示方法的:</code><!--=)<-->
预查内容↓ \ 方向→ 向后(左) 向前(右) 存在\(子模式\)\@<=< code> <code>\(子模式\)\@=</code> 不存在 <code>\(子模式\)\@<!</code> <code>\(子模式\)\@!</code><blockquote><span> 💡 <strong>预查</strong>即预先检查子模式,看看这个子模式是否存在于待匹配的字串前/后,预查子模式是<strong>不会出现在最终的匹配结果中的</strong>。</span></blockquote><span> <img src="https://assets.xbottle.top/img/lookBehindPositive-2022-04-22.jpg"></span><blockquote><span> 👆 匹配<code> paprika</code>,前提是<code> paprika</code><strong>后面</strong>(左边)必须要匹配到<code>paprika</code>。</span></blockquote><span> <img src="https://assets.xbottle.top/img/lookAheadPositive-2022-04-22.jpg"></span><blockquote><span> 👆 匹配<code>paprika</code>,前提是<code>paprika</code><strong>前面</strong>(右边)必须要匹配到<code> pepper</code>。</span></blockquote><span> <img src="https://assets.xbottle.top/img/lookAheadNegative-2022-04-22.jpg"></span><blockquote><span> 👆 匹配<code>paprika</code>,前提是<code>paprika</code><strong>前面</strong>(右边)<strong>不能</strong>匹配到<code>pepper</code>。</span></blockquote></code><!--=<-->
- 搜索 光标下的单词 ; 这一小节的操作是在
命令模式/正常模式
下的:*
往后搜索 光标目前指向的单词,只匹配 一整个单词#
向前搜索 光标目前指向的单词,只匹配 一整个单词
从这个例子可以看到,实际上Vim是把光标指向的单词转换成了搜索语句。
*
对应/\<accept\></accept\>
,#
对应?\<\accept\><!--\accept\-->
。g*
往后搜索 光标目前指向的单词,单词可作为 字串的一部分被匹配。g#
向前搜索 光标目前指向的单词,单词可作为 字串的一部分被匹配。
可以看到
*
对应/accept
,#
对应?accept
,单词可作为 字串的一部分被匹配。
💡 因为这几个指令被转换为末行搜索操作了,所以在搜索中可以用的n
、N
这一类指令也是可以用的。
- 开启 搜索高光显示 上面的图示中搜索匹配项都会” 黄的发光“,这种 匹配结果高光显示是可以作为配置项使用
:set
进行设置的::set hlsearch
或:set hls
开启搜索结果 高光显示:set nohlsearch
或:set nohls
关闭搜索结果 高光显示 虽然高亮显示一目了然,但是开了之后光标就不明显了,高光咱已经看够了,怎么 关掉目前结果的高光展示呢?:nohlsearch
或:noh
关闭 目前的高光显示
可以看到输入
:noh
后会取消目前的高亮,但是这并不影响重新开始搜索时高亮展示匹配。
💡 记忆方法:hlsearch
即Highlight Search
,Highlight [v]突出,强调
,Search [n]搜索
。
- 替换 ; 替换的指令就是在
末行模式/命令行模式
下输入的了, 其完全可以结合搜索指令一起记忆::[作用范围] s/<搜索模式>/<替换模式>/<替换flag><!--替换flag--><!--替换模式--><!--搜索模式-->
💡 很明显了,这里的
s
代表的就是substitute [v]取代,替代
- 作用范围 这里直接列表直观展示一下:作用范围 说明 不写 默认光标所在行
.
同样代表 光标所在行n
(整数) 代表 第n
行。比如233
代表第233行$
代表 最后一行'a
代表a
标记所在行(关于设定跳转标记可以看自定义跳转标记)上述符号±相对行数
比如'a+2
就代表a
标记所在行的下面第二行;.-1
就代表光标所在行的上面一行上述符号1,上述符号2
代表从上述符号1
代表的行到上述符号2
代表的行。比如.,$
代表从光标所在行到最后一行。%
代表 从第一行到最后一行(整个文本),和1,$
相同'<,'><!--,'-->
在可视模式下输入:
进入末行模式/命令行模式
会自动填充,代表**可视模式下选定的范围
👆 示例:
.,+3
代表从光标所在行到光标所在行的下面第三行作为范围进行替换 - 搜索模式 ; 同上面的搜索模式。 💡 值得一提的是这里可以留空。如果留空的话 默认使用上一次搜索的匹配。
比如我先搜索了
/\<paprika\></paprika\>
,然后我想替换全文的/\<paprika\>/</paprika\>
为pepper
,在替换时可以这样写::%s//pepper/g
(省略了搜索模式)。 - 替换模式 替换模式当然可以是 任意字符串, 同时也可以 引用搜索结果中的部分: 👆 使用
\1
,\2
引用 搜索结果中的第一个和第二个 捕获组的内容。 👆 使用&
引用 搜索匹配结果 👆 很巧妙的用法,利用捕获组引用交换顺序 - 替换flag ; 一般正则表达式末尾会加上修饰符以控制匹配行为。而Vim这里的 替换flag也是类似修饰符,控制替换行为的。 下面列出几个比较常用的:Flag 说明 记忆
g
全局替换(在指定的 作用范围内)global [a]全局的
i
忽略大小写ignore-case 忽略大小写
I
大小写敏感 和i
意义相反n
并不会真正替换,而是显示 匹配的数目numerate [v]计算
c
在替换前 让用户确认confirm [v]确认
💡 值得一提的是
i
——忽略大小写。
之前在搜索模式中提到过在模式中加入\c
能忽略大小写进行搜索,而这里替换也是用的搜索模式,
因此在这里就算不用修饰符i
,转而在搜索模式中加入\c
也是完全可以的。
👆 不使用修饰符而是在搜索模式中使用了\c
👆 使用n
修饰符,并不会实际替换文本,而是 显示匹配的数量
👆 使用c
修饰符,在替换前 让用户确认。 其中提示输入的(y/n/a/q/l/^E/^Y)
中,分别代表:输入指令 说明 记忆y
确认替换 当前光标所在匹配yes [v]确认
n
不替换 当前匹配no [v]不
a
确认替换 所有匹配all [v]所有
q
不进行替换并退出quit [v]退出
l
替换 当前匹配并退出instead [adv]顶替
(另还有Ctrl+E
和Ctrl+Y
,是光标移动指令)
除了这些,搜索替换可能还有一些其他的用法尚未提到,另外还有 :g
这种末行指令。这里就主要记录一下基础的用法啦~
简单多窗口编辑
一个文件一个文件地打开编辑老累了,幸运的是,Vim支持多窗口编辑。
- 打开新窗口 ;
:new [filename]
使用:new
指令能在 编辑器顶部新建一个横向窗口(原本的文件窗口会 下移) 如果有指定 文件名,则会在新窗口打开指定文件(文件不存在就是单纯的创建buffer):sp[lit] [filename]
(也就是:sp
和:split
都可以) ; 这个指令行为上和:new
挺类似的,都会新建一个 横向窗口,使原本的窗口 下移。 不同的是, 没有指定文件名时会在新窗口打开 当前编辑的文件!
👆 split [v]划分,分割
:vs[plit] [filename]
这个指令和:sp[lit]
类似,但是:vs[plit]
是新建一个 纵向窗口,使原本的窗口 右移。 和:sp[lit]
一样的是, 没有指定文件名时会在新窗口打开 当前编辑的文件
👆
:vsplit
即vertical split [v]垂直分割
- 在窗口之间切换 ; 开了这么多窗口,得想个法子来回切换哈!
Ctrl+w
或Ctrl+W
( 可以记成Control Window 指挥窗口
) 连按两次Ctrl+w/W
可以在 窗口之间循环切换Ctrl+w/W+方向控制键
; 对于 分割成上下关系的窗口,可以使用Ctrl+w/W+↑/↓
或Ctrl+w/W+k/j
来进行上下切换 而对于 分割成左右关系的窗口,就可以用Ctrl+w/W+←/→
或Ctrl+w/W+h/l
来进行左右切换- 调整窗口尺寸 在调整终端尺寸的时候,Vim里的这些窗口可能并不会如意调整展示尺寸。这里记录一些改变窗口尺寸的指令:
- 调整窗口高度
:res[ize] [±][height]
第二种是设置 相对高度,比如:res[ize]
指令有两种调整 窗口高度的方法。 第一种是设置 绝对高度,比如:res 5
,将窗口高度设置为5
行::res +5
,将窗口高度增加5
行: - 调整窗口宽度 ;
:vert[ical] res[ize] [±][width]
和:res[ize]
类似,:vert[ical] res[ize]
也是能相对/绝对地调整 窗口宽度的:
💡 这个记起来可能有点反直觉,
vertical resize 垂直方向上调整
,可以 记作此时只有 垂直高度固定的窗口,所以调整的是 宽度;
而普通的resize
则是调整的 窗口高度,可以 记作此时只有 水平宽度是固定的窗口。 - 退出窗口 同
末行模式/命令行模式
下的:q 退出
可视模式
前面的说明在几个方面提到了视觉模式:
[En]
The previous note refers to * visual mode * in several areas:
可视模式下的操作可谓是 简化版的 命令模式/正常模式
了,显而易见,”简化”的就是”选择文本”的操作了。
在高光选择了文本后可以进行以下操作:
- 拷剪粘三件套 这里和
命令模式/正常模式
的不同之处就在于文本已经选择完毕,只需要 输入一个指令就可以完成简单的编辑操作。 y
输入一次即可拷贝 选择的文本,而Y
则是拷贝 所有选择文本所在的行 (Yank
)d
输入一次即可剪切 选择的文本,D
也是会剪切 所有选择文本所在的行的。(Delete
)x
和d
操作一致 (给文本画叉叉)c
和d
操作一样,不过剪切完之后会 进入插入模式p
在选择的区域中 粘贴文本 (Paste
)- 替换 ;
r<字符><!--字符-->
将所选文本替换为<字符><!--字符-->
(Replace
)
👆
ra
将所选块文本全部替换为了a
- 行连接 这一部分和
命令模式/正常模式
下的行连接指令几乎是一样了。 J
将所选文本 对应的行连接成一行, 用空格间隔 (Join
)gJ
将所选文本 对应的行连接成一行, 没有间隔- 执行
末行模式/命令行模式
指令 ; 在可视模式下选择文本后输入:
进入末行模式,会 自动填充成:'<,'><!--,'-->
,这代表在 所选文字中进行末行语句操作。 之前的搜索替换中就有提到过:基本搜索替换->作用范围 - 代码缩进 在
命令模式/正常模式
下要对一行代码进行缩进操作,往往需要输入两次>
或<
而在可视模式下只需要输入一次:
👆
>
将所选文本增加一次缩进
👆<
将所选文本减少一次缩进(因为选择不完全,只减少了一部分)
👆>
将所选文本增加2
次缩进 - 大小写转换 ; 这一部分和
命令模式/正常模式
下的大小写转换指令是很类似的: u
将所选文本转换为 小写U
将所选文本转换为 大写 (UPPERCASE
)~
将所选文本中的 大写和 小写分别转换为 小写和 大写
👆 演示了一下使用
~
进行大小写转换
视觉模式有很多用途,所以这里不会再有写作(如果你写得更多,它将成为一本语法手册。嘿!)
[En]
There are many uses of visual mode, so there will be no more writing here (if you write more, it will become a grammar manual. Hey! )
In the end
回过头来…我又写了这么长一篇笔记…稍后我会完善一下目录功能以增加阅读体验。
这篇笔记虽然写得多,但是涉及的内容实际上还是 比较浅层的,毕竟这篇笔记主要目的是为了记忆 常用方法。也就是说, Vi/Vim
的使用技巧远不止这么一点,更多高级的操作还需日常多加使用才能更加熟练!
由于个人能力极其有限,文章中可能存在一些错误。如果有什么错误,请多指教!
[En]
Due to the extremely limited personal ability, there may be some mistakes in the article. If there are any mistakes, please give us more advice!
最后…感谢你读到这里,再会~
Original: https://www.cnblogs.com/somebottle/p/vi_vim_memorizing_tricks.html
Author: SomeBottle
Title: 想法子记忆Vi/Vim常用操作及指令
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/523770/
转载文章受原作者版权保护。转载请注明原作者出处!