Vim复制行的范围

98

我是一名C#开发者,最近决定扩展自己的工具知识。我决定学习的第一个工具是Vi/Vim。到目前为止一切都进展顺利,但是有几个问题我找不到答案:

  1. 假设我想要拷贝一段行数范围内的内容。虽然有很多方法可以实现,但我想按行号来选取。我认为它应该与替换命令类似,像81,91y这样。有没有办法做到这一点?

  2. 我对普通模式下的g命令有些困惑。它似乎能做很多事情,我无法确定g命令在本质上是运动命令或其他通过普通模式运行的命令的“通用”命令。请问有人能够解释这个或指向一个好的g命令的参考资料吗?


1
你知道在vim(1)中的命令“:help”吗? - Steve Emmerson
是的,但我在所有的参考资料中都找不到它。结果我想从正常模式下完成它,但hometoast展示了如何从命令模式下完成。对于g命令,我发现帮助文档没有像其他命令那样将所有内容联系起来。 - jnadro52
3
作为附言,我建议您每个问题发布一个帖子。 - Dana
1
我将来会这样做。我更关心第一个问题,只是在打第一个问题的时候才想到了另一个问题。 - jnadro52
10个回答

160

复制第81-91行

:81,91y<enter>

如果你的手指不喜欢找冒号和逗号键,这个方法也可以(跳到第81行,复制11行)。
81gg11yy 

我的唯一使用 g 的方法是 5gg。用于跳转到第5行。22gg: 第22行。正如jimbo所说,它实际上只是其他一些命令的修饰符。

为了完整起见,(http://vim.wikia.com/wiki/Power_of_g)解释了在命令模式下g的许多工作原理。


3
使用大写字母也提供了不同的变化:'gg'将移动到第一行,而'G'将移动到最后一行。此外,'5G'会跳转到第5行。标记也可以用来代替行号(适用于宏),例如:':‘a,52y'。 - NVRAM
1
如果你不怕Shift键,81G11Y甚至更“短”。 - Jens
1
正常模式方法的缺点是你会失去你的“位置”;你可以在mx之前和'x之后,但是命令模式版本变得更加简洁。嗯...我刚写完这个就看到了@Asta的答案。 - Eric Smith
1
@WilliamRoss 这实际上是将这些行放入 Vim 的缓冲区中,而不一定是您系统的剪贴板,您可以使用 CTRL+V 将其粘贴到其他应用程序中,例如记事本。请参阅相关问题:如何从 vi 复制/粘贴文本到不同的应用程序 - hometoast
1
这让我感到有趣,因为我寻找第一个解决方案的整个原因是为了避免在脑海中计算行数或进行减法运算。 - Paul Parker
显示剩余2条评论

28
你也可以使用't'命令将当前行复制到光标位置。
:81,91t.<enter>

这将在光标所在行下方粘贴第81-91行内容。
我从VIM优秀资源网站http://vimcasts.org学到了这个技巧。

这里的t.是什么意思? - CivFan
3
据我理解,t可以被视为“直到”或“至”,而.是当前行的地址。 - Asta
1
@CivFan 是 :copy 的同义词。 - D. Ben Knoble

16

G命令在搭配计数值时,可以定位到指定行号。例如81G会把光标移动到第81行。

y命令可以和类似G的动作结合使用。因此,要复制从当前行到第91行的所有内容,可以使用y91G命令。

两个命令结合起来就是:

81Gy91G

前往第81行,在前往第91行的同时复制。


2
我希望我可以多次点赞。对我有帮助的是使用这个命令将文本复制到寄存器(在我的情况下,是寄存器+即剪贴板):81G"+y91G - mgarey
1
@mgarey,使用行范围语法没有直接将内容复制到寄存器的方法吗?例如81,91y并以某种方式指定寄存器? - diplosaurus
1
@diplosaurus 可能是,但我不确定。如果这个问题在vi.stackexchange.com上还没有或者不在这里的话,你可以去那里问一下。我会很感兴趣的。我不是Vim专家。 - mgarey
3
@mgarey需要用谷歌搜索找到答案,但我在这里找到了:https://stackoverflow.com/questions/16225366/vim-to-delete-a-range-of-lines-into-a-register。 :81,91y +的意思是将第81行到第91行的内容复制到寄存器中。 - diplosaurus
1
我已经想通了!:81,91y a 可以正常工作,但如果你想要复制到 +* 寄存器,则需要在前面加上 ",例如 :81,91y "+ - ojunk
显示剩余4条评论

15

我也喜欢使用vim的相对行号选项(set rnu),这意味着我只需要输入:

:-10,-7ya a

将文本复制到命名缓冲区a中。

注意:指定A将把您要复制的内容附加到缓冲区a的当前内容中。

不要忘记,您还可以使用类似的命令复制文本块并移动文本块:

:-10,-7co .

意思是将当前行以下的四行文本复制到当前行以上十行。

:-10,-7mo .

意思是将当前行下面的四行文本向上移动10行。


5

除了使用y命令将第91到96行复制到寄存器a中(使用"ap黏贴),还可以使用以下命令将复制的行追加到寄存器中:

:91,96y A

即,将 A 寄存器大写会将内容追加到寄存器 a 中而不是覆盖。寄存器的大小写始终如一,例如,:let @A=';' 会将 ; 追加到寄存器 a 中。
使用加号(+)或减号(-)可以相对于当前光标位置引用行:
:-10,+10y b

例如,它将沿着当前光标位置抓取(y)21行并将它们放入寄存器b

实际上,缺少输入表示当前光标位置,这意味着这样做:

:-5,y a

将当前光标位置上方5行的文本提取到名为a的缓冲区,并进行以下操作:
:,+5y a

将当前光标位置后的5行文本复制到缓冲区a中。

注意:如果您在缓冲区a中有一个宏,它将被前面的复制覆盖,因为复制寄存器和宏寄存器实际上是相同的东西。这也是为什么,巧合的是,您可以粘贴一个宏、编辑它,然后再将其复制回它的寄存器中。我个人使用左手可达的字母来进行复制,右手可达的字母来进行宏操作。

移动文本块的操作如下:

:+10,+13m.

意思是将当前光标位置前10行的四行文本移动到当前行下方。
附言:
之前我曾经把 ":91,95ya a" 中的 "ya" 和 "ya{motion}" 混淆,以为 "a" 是由 "91,95" 提供 motion 的同义词。这是错误的,在“ya”中的“a”是完全不必要的。在我的辩护中,我的“help yank”没有说明“ya”是“yank”的可能别名。

1
“:ya” 是 “:yank” 的缩写,所以我不确定对于“yanks all lines” 的感觉如何。但是很好地压缩了一些分散的信息。 - D. Ben Knoble
我也曾这样认为,直到我查看了:help yankyank 没有别名 ya。不过你说得对,a 并不代表“全部”,它实际上代表的是“a”。不过我仍然更喜欢说“全部”,因为这对我来说更有意义。 - Paul Parker
2
:[range]y[ank] [x] Yank [range] lines [into register x] the square brackets in y[ank] indicate that the [ank] are optional. :y, :ya, and :yan are implicitly aliases for :yank - D. Ben Knoble
我改正了 :) 不需要加"a"。会修改答案以反映这一点。 - Paul Parker
1
你的补充很好,但我指的是你的第一行,你使用了ex命令:ya而不是正常命令y - D. Ben Knoble
哦,ya是从ex遗留下来的。来自ex手册的描述:( . , . )yank buffer count abbr: ya - Paul Parker

4

g本身并没有任何作用。它是几个元命令之一,包含了许多有点不相关的命令。

z也是一个类似的命令。


谢谢。我现在明白它只是用于不同的目的。当我尝试学习这些工具时,我会尝试将命令与某些抽象的东西相关联,以便记住如何正确使用它。看起来 g 命令只是你需要记住才能正确使用的其中一件事情。 - jnadro52

3
最好的解决方案是进入 “可视模式”,按 v 键。选择要复制的行,然后按 y 键进行复制。然后按 p 键粘贴已复制的行。

不同意,只是因为可视模式有时太慢了。 - D. Ben Knoble
如果您想要复制其他运动命令无法获取的行范围到寄存器中,那么使用“ay”或类似命令非常有用。在选择后使用即可。 - chipfall

2

Vim的:help indexg描述为:

|g|             g{char}            extended commands, see |g| below

向下滚动(或使用:help g)查看列表。


1
我熟悉:help,但不熟悉:help (command)。这在以后会非常有用。非常感谢您,先生。 - jnadro52

2
作为长期使用 Vi/Vim 的用户,我倾向于使用“标记”而非行号(或“行标记”)。使用方法如下:m 是“标记”字符;然后使用任何字母来标识/命名该标记。要返回到标记,请在命名的标记前加上单引号('a)。这些标记可以用作范围。例如:
File:
    <line 1>
    <line 2>
    <line 3>
    <line 4>
    <line 5>

在命令模式下,将光标移动到第二行,键入ma。滚动到第四行,键入mb。 要从标记a复制至标记b,请键入:

    :'a,'byank

要从标记a到标记b删除,请输入:

    :'a,'bdel

从标记a到标记b搜索并将“ine”替换为“ink”:
    :'a,'bs/ine/ink/g

要复制标记a到标记b并粘贴到当前位置下方(“点”始终引用光标当前所在的行):

    :'a,'bco . 

将代码行,在标记a到标记b之间,向右移动一个制表符(使用相反的尖括号<来向左移动):
    :'a,'b> 

在命令模式下,您可以通过键入'a返回标记行a。键入''将使您返回到上一个位置(不幸的是,它只能记住上一个位置,而不能回退两个位置)。

您可以复制、删除行、搜索和替换代码的部分等操作,而无需知道行号,并且可以将其保存到命名缓冲区中。


https://vim.fandom.com/wiki/Cut_or_copy_lines_without_counting_the_lines 提供了一种更加简洁的标记使用方法。 - Thomas Hedden

1

要从第81行到第91行拷贝:

方法1:81gg11yy

还不错,但你需要进行一些计算来确定要拷贝多少行

方法2:81gg 然后 shift+v 然后 91gg 然后 y

在我看来是最好的方法,因为这是直接的,你只需要知道明显的事情,即从哪一行到哪一行你想要拷贝


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