我该如何在Vim的可视模式下将文本块保存到文件中?

80
标题非常具有描述性。以防万一,我会举一个例子:
START BLOCK1
something
END BLOCK1

START BLOCK2
something
somenthing...
END BLOCK2
  1. 我在可视模式下选择 BLOCK1
  2. 按下 y 键进行复制
  3. 如何将复制的BLOCK1保存到其他文件中?
8个回答

147

选择您想要保存的文本,可以是行可视模式或块可视模式,并

:w new.txt

这是你要输入的内容,但实际上你不会看到与之对应的内容。当你按下:键时,你会进入命令行界面,该界面将自动填充所选信息。它会像这样:

:'<,'>

继续输入剩余部分 (w new.txt) 以获得

:'<,'>w new.txt

...然后按下回车键。


19
这并不能产生期望的结果,因为它只会写入完整的行,而忽略了所选区域的起始和结束位置。有什么解决办法吗?否则我想重新提交主要问题。 - dronus
2
@dronus - 我不太明白你在问什么。根据我对问题的理解,这个代码已经实现了OP所要求的功能。 - Rook
7
如果您在任何非行级别的可视模式中进行选择,:w仍会写出所选范围内所有涉及的完整行,但不包括行内的起始或结束位置。例如,如果您在块选择模式下选择一个狭窄的列,或者在可视选择模式下选择一行的部分内容,则:w将写入整行,即使y能正确地复制行的相应部分。 - dronus
1
@dronus - 啊,好的。是的,那是正确的。但是,虽然我不能代表其他人说话,但它对我来说是预期的行为。 - Rook

18

选择块后,您可以使用:'<,'>w other-file,将仅写入所选块到other-file。在可视模式下按下:会自动将'<,'>放入命令行中,因此您只需要键入:w other-file


3
Vim 总是选择整行用于管道传输到外部命令,所以您可以使用 Unix/Cygwin 的 "cut" 命令来选择选定区域中每行的列 N 到 M::'<,'>w !cut -cN-M > new.txt。最高票答案和读者似乎不理解问题,这让人感到惊讶。 - mosh
@mosh 但是当所选文本未对齐到列时,这也不起作用。 - Sajuuk

7

也许有更简单的方法,但我会创建一个新缓冲区(或选项卡),然后使用p将其粘贴进去。您可以使用:new创建新缓冲区,或使用:tabnew创建新选项卡。您可以像平常一样使用:w filename将缓冲区/选项卡写入文件中。


2
请确保删除顶部的额外行!(将内容粘贴到空缓冲区会在顶部创建额外行,或者如果使用 P,则在底部创建额外行。) - lmat - Reinstate Monica

3
与@songz的解决方案类似,我更喜欢使用“:new”进行操作。
vmap <C-c> y:new ~/.vimbuf<CR>VGp:x<CR>:!pbcopy < ~/.vimbuf<CR><CR>

据我所知,pbcopy 只存在于 OSX 上。虽然在 Linux 和其他系统上有类似的程序,但它们使用不同的名称并且工作方式也不同。 - Josh Rumbut
是的,它只在pbcopy可执行文件存在时才能工作 :) 所以完全没有任何危害。 - chenkaie

3

像 @dronus 在评论中提到的那样,:w !pbcopy 命令无法正确复制,因为它会复制整行。如果我只想复制一行中的 url,那么就做不到了。下面是一行代码,您可以将其添加到您的 .vimrc 文件中,这样每次按下 CTRL-C 键时,您在 vim 中选择的行都会被复制到剪贴板中:

map <C-c> y:e ~/clipsongzboard<CR>P:w !pbcopy<CR><CR>:bdelete!<CR>

如果您想了解更多关于此操作的详细信息,可以在我的博客中阅读相关内容。这是与@rmeador建议的实现方式相同的实现。

2
使用Vim获取视觉选择并保存到文件中:
    function! Get_visual_selection()
        "get the position of left start visual selection
        let [line_start, column_start] = getpos("'<")[1:2]
        "get the position of right end visual selection
        let [line_end, column_end] = getpos("'>")[1:2]
        "gotta catch them all.
        let lines = getline(line_start, line_end)
        if len(lines) == 0
            return ''
        endif
        "edge cases and cleanup.
        let lines[-1] = lines[-1][: column_end - 2]
        let lines[0] = lines[0][column_start - 1:]
        return join(lines, "\n")
    endfunction

    function Save_visually_selected_text_to_file()
        let selected_text = Get_visual_selection()
        call writefile(split(selected_text, "\n"), "/tmp/something.txt")
    endfunction

    "the c-u does a union of all lines in visual selection.
    "this goes in the vimrc
    vnoremap <F10> :<c-u>call Save_visually_selected_text_to_file()<cr>

0
基于 @chenkaie 的变体,对我很有效: let mapleader = "," let g:mapleader = "," vmap y y:new ~/.vbufVGp:x nmap p :r ~/.vbuf

0

除了上面selected的答案之外,

  • 当使用鼠标选择时(1),

  • 以及@dronus的评论中提到的仅复制整行的问题,当只想部分复制行时(2):

(1)在我的基于Debian的DietPi(Raspberry PI)系统上,当我在Ubuntu 16.04工作站上使用鼠标进入和选择“VISUAL MODE”时,vim的操作与上面的首选解决方案有所不同。然后

  • y来复制它

但如果我键入“:”进行命令,它将不会显示出来。

'<,'>

在哪里我可以简单地添加我的

w new.txt

之后。所以我就自己输入它,然后它确实起作用了:

'<,'>w new.txt

它将整行(行)复制到我的文件“new.txt”中,而“<,”似乎意味着“复制选定的行”,并将“>”重定向到写命令引用的文件。

(2)对于不粘贴部分行的问题,就像@dronus comment提到的那样,this解决方案(第一个选择)适用于我:

编辑第一个文件,复制您想要的文本。然后从vi中打开第二个文件(:e /path/to/other/file),并将其粘贴(通过键入p)。保存它(如上面的“:w new.txt”。

然后它只会复制由鼠标或光标标记的行的一部分。

[编辑] 在我的Ubuntu系统上:有时在vim中选择文本时,鼠标并不会进入“可视模式”。这时可以使用上下文菜单选择普通的复制/粘贴操作...我还没有找到Ubuntu为什么会将其行为从“客户端行为”更改为“主机行为”的原因(Ubuntu托管ssh bash窗口到我的“客户端”)...


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