你在使用Vim时遇到的问题是你不理解vi。

3
我们可以使用m来移动行,使用j来连接行。例如,如果您有一个列表,并且想要将所有匹配(或相反,不匹配)某个模式的内容分开,而不删除它们,则可以使用以下命令::% g/foo/m$ ... 然后所有“foo”行都将被移动到文件的末尾。(请注意另一个提示,即将文件末尾用作草稿空间)。这将保留所有“foo”行的相对顺序,同时将它们从列表的其余部分中提取出来。(这相当于执行以下操作之一:1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d(将文件复制到自己的尾部,通过grep过滤尾部,并从头部删除所有内容)。)
阅读Jim Dennis的这篇传奇回答,但我仍然无法理解这个序列: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d 有人能帮忙解释一下吗?GGmap是什么?为什么1G! GGmap之间有一个感叹号?Ggrep是否来自vim-fugitive?

1
请在 https://vi.stackexchange.com/ 上尝试。 - Ôrel
1个回答

5

这个命令中的所有部分都很好理解,除了 !GG 部分。让我们来分解一下整个命令:

1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
  1. 1G 将光标移动到第一行,参见:help G
  2. !GG 没有意义
  3. ma 创建标记a,参见:help m
  4. p 在光标后插入未命名寄存器的内容,参见:help p
  5. !Ggrep foo<ENTER> 使用外部命令grep foo从当前行到最后一行过滤行,参见:help !
  6. 1G 将光标移动到第一行。
  7. :1,'a g/foo'/d 删除从第一行到标记a之间所有包含foo'的行,参见:help :range:help :g:help d

我认为步骤2是一个打字错误。!GG 字面意思是“使用外部命令G从当前行到最后一行过滤文本”,这没有任何意义,因为a) G不是常见的Unix命令(如果它存在的话),b) 它没有后跟<ENTER>,而这是执行Ex命令所必需的。

该步骤应该执行的操作在答案正文中描述:复制缓冲区的内容。有很多方法可以完成这个操作,但是:

yG

从这里到最后一行进行剪切,然后执行以下操作:
G

把光标放在最后一行,更适合这种情况。所以整个序列实际上应该是:

1GyGGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d<ENTER>

这适用于Vim和vi。

--- 编辑 ---

请注意,还有一些可以改进的空间。以下序列具有相同的结果,但不需要不必要的光标移动:

:$ka|r!grep foo %<ENTER>:1,'ag/foo/d<ENTER>

它也适用于 ex ;-).

另一个优化版本,有点与答案试图演示的相反(将文件顶部作为草稿区而不是底部),但结果完全相同:

:0r!grep -v foo %<ENTER>:+,$v/foo/d<ENTER>
  • 没有正常模式下的光标移动,
  • 没有书签。

但说实话,这个问题并不需要复杂的解决方案,只需要用简单的方式解决:

:g/foo/m$

该命令可以在 ex、vi、所有 vi 克隆版本甚至 ed 中使用。


我对!GG也有同样的感觉,它几乎没有意义。我更或多或少地弄明白了ma(a),所以我假设'p'与GG有一定关系。谢谢。 - mtjing

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