VIM - 解释“normal”和“global”命令

3
有人能为我解释一下在VIM中全局命令(:h :g)和规范命令(:h norm)是如何工作的吗?我有一个文件:
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
G
H

我发出了:g/[0-9]/norm 4gg dd,希望它能按以下方式工作:

  1. [0-9] = 只匹配有数字的行
  2. 4gg = 跳转到第4行
  3. dd = 删除当前(第4行)行

所以我期望得到这样的结果:

1
2
3
5
6
7
8
9
A
B
C
D
E
F
G
H

但是我得到的却不是它:
1
2
3
4
A
B
C
D
E
F
G
H

此外,我使用normnorm!都没有关系,它们有什么区别?您能否为我解释一下它是如何工作的或指向一些好的参考资料?我已经阅读了:h :g:h :norm,但这并没有帮助。谢谢。
PS:我可以使用:4d,但我对:g:norm的解释感兴趣,问题只是举了一个简单的例子。
4个回答

8
:g/pattern/do something

"will do"在每一行中匹配到"pattern"的部分都会执行"do something",因此你将得到这样的输出。

尝试一下:

:g/\d/echo getline('.')
:g/\d/echo line('.')

第一行打印匹配的行,第二行打印匹配的行号。

因此,对于每个匹配的行,vim会执行某些操作(在本例中为echo)。

至于为什么4还在那里,因为4ggdd之间有一个空格。

您的带数字的行只有一个字符,因此空格会将光标移动到下一行。这就是为什么4不会被删除的原因。

去掉空格


4
顺便提一下(几乎完全不相关),:g/pattern/do somethinggrep得名的来源:g/regular-expression/print -> g/re/p - sanmiguel

7

:normal

:{range}normal {command}

{range}范围内,对每一行执行普通模式命令{command}。如果没有指定{range},则只在当前行执行。

例如:

:5,18normal 0df=

:global

:{range}g/{pattern}/{command}

仅在匹配 {pattern} 的行中,在 {range} 上执行 {command}。如果没有指定 {range},则对整个缓冲区执行。

示例:

:5,18g/^foo/normal 0df=
:5,18g/^foo/s/^.\{-}=/

2
这意味着:
对于每一行包含数字 0 到 9 的情况,转到第四行并删除它。因此,在第一次迭代中,它删除数字 4,在下一次中删除数字 5,以此类推。当光标开始在不包含数字的行上时,它不匹配并且不执行“normal”指令,因此不删除任何内容。

这本来是我的答案。不幸的是,它并没有删除第四行。由于某种原因它删除了第五行(你可以在输出中看到 OP 给出的那个 4 仍然存在,我也能够复现这种行为)。我不知道为什么会这样。你知道吗? - Cubic
1
@Cubic:据我所知,normal命令会在不加空格的情况下执行其参数,例如::g/[0-9]/norm 4ggdd,这样是可以正常工作的。但如果加上空格,对我来说就无效了,什么也不会发生。 - Birei

2
为了回答你的问题(请注意,除非紧密相关,否则询问几个问题是不好的风格,并且你应该能够通过优秀的:help解决大部分问题): :normal:normal!之间的区别在于前者考虑映射,而后者始终使用默认的Vim命令。因此,前者适用于临时命令(利用您的映射),但后者建议用于插件(以独立于任何映射)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接