Vim:将选定的文本传输到shell命令并在vim信息/命令行上接收输出

71

我想将所选文本导入到shell命令中,并在vim信息/命令行上接收这个shell命令的一行输出?

我真正想做的是:将所选文本传输到pastebin类型的shell命令中,并希望接收shell cmd的输出(即pastebin的http链接)。这可能吗?


1
与将选定文本作为STDIN提供给shell命令相关的问题:用shell命令输出替换选定的原始文本在vim中使用管道与整个缓冲区交互 - user1129682
7个回答

138

对于多行版本,选择文本后可以执行以下操作:

:'<,'>:w !command<CR>

请查看官方的Vim文档,网址为:help :w_c.


你可以像这样将它映射到简单的可视模式快捷方式:

xnoremap <leader>c <esc>:'<,'>:w !command<CR>

在可视模式下按下<leader key>+c,将选择的文本发送到命令的标准输入(stdin)。命令的标准输出(stdout)将会打印在vim状态栏下面。

CoffeeScript的实际示例:

https://github.com/epeli/vimconfig/commit/4047839c4e1c294ec7e15682f68563a0dbf0ee6d


33
不加 ":w" 将用命令的输出替换所选内容。 - Clint Pachl
8
我不理解这个:w的语法和作用方式。它是正常的“写入”命令吗?第二个冒号有什么作用?你能解释一下吗?谢谢! - schoettl
1
我正在使用的映射变体:xnoremap <expr> <Leader>c "\<Esc>:'<,'>:w !" . getbufvar('%', 'run_command', &filetype) . "\<CR>"。这将使用缓冲区的 filetype 作为命令,适用于许多语言(如 rubypython 等)。您仍然可以通过设置 b:run_command 来覆盖此设置,这对于嵌入在 Markdown 文件中的代码非常有用。 - Martin Tournoij
3
@schoettl 我也在想同样的问题!可以在:help :w下找到相关内容,具体地说是:help :w_c - Mihai Alexandru Bîrsan
1
这将适用于基于行的选择,但如果仅选择了行的特定部分,则此方法将无效。 - caltuntas

44

只需使用可视化行选择Shift+V突出显示代码行,然后按:!并键入您要发送到命令的命令。生成的输出将替换您选择的文本。

输入您的命令时,它将出现在底部:

:'<,'>!somecmd

'<,'>是指您在视觉上选择的范围将被传递到感叹号后面指定的命令中。


12
这只是用 shell 命令的输出替换所选文本。 - ikwyl6
抱歉,我误解了问题。我以为那是你想要做的事情。 - Neg_EV
6
这个版本有它的优点。完成这个版本之后,您可以复制/粘贴命令输出。使用Shift-v选择并按y键,如果它是一行,则按yy键等,撤销以恢复原始状态(按u键),然后粘贴(按p键)复制的命令输出。这样,您就可以在当前缓冲区中同时获得原始数据和pastebin网址,无需任何额外的Vim配置,也无需使用鼠标来获取命令输出。 - fess .
2
将某些cmd sh设置为实际的shell命令。例如::'<,'>!sh - Salami

19
我会这样做:
将这个函数放到你的vimrc文件中:
function Test() range
  echo system('echo '.shellescape(join(getline(a:firstline, a:lastline), "\n")).'| pbcopy')
endfunction

这将允许您通过以下方式调用此函数:

:'<,'>call Test()

然后你也可以像这样映射它(就在vimrc中函数声明下面):

com -range=% -nargs=0 Test :<line1>,<line2>call Test()

那么你可以通过调用函数来实现这个操作:

:'<,'>Test

注意::<','>是区间选择器,要生成它们,请在可视模式下选择相关行,然后进入命令模式(按冒号键)。


1
非常好的答案,而且它有效。唯一的问题是在 pastebin 上无法解释 vim 中的新行。因此,如果我在 vim 中选择多个行,它会显示为一个大行在 paste bin 上。有没有办法解决这个问题? - ikwyl6
2
对我来说,它生成了这个:http://pastebin.com/8XuqTr1K(每行末尾都有«\»)。我正在使用来自Gentoo存储库和zsh的pastebin-0.6.1。 - ZyX
1
我通过换行符解决了我的问题:我在上面的Test()函数中将'\n'更改为'\r'。现在它在pastebin上显示实际的新行。 - ikwyl6
2
好的,再添加一个问题:您知道如何将此脚本在vim系统命令行上显示的http链接复制到系统缓冲区吗?(即:*y) - ikwyl6
1
我稍微修改了一下,因为每行末尾都会出现反斜杠字符,改为:echo system('pbcopy', join(getline(a:firstline, a:lastline), "\n")) - Sam Jacobson
显示剩余2条评论

7
也许你应该使用类似的东西。
:echo system('echo '.shellescape(@").' | YourCommand')

从vim-7.4版本开始,最好使用

:echo system('YourCommand', getreg('"', 1, 1))

这基本上是保持文件中的NUL字节不受影响的唯一方法。以任何一种方式传递@"都会将NUL字节转换为NL(换行符)。


这看起来不错。有一点小问题,就是在选定文本后,你必须使用 “y” 键进行 “抓取”,然后再运行该命令。仅在视觉模式下选择文本并运行该命令会出现 E481:不允许范围 - davr
1
这个基本思路可以简化为:call system('YourCommand', @")。映射将为您执行必要的复制操作。总体来说,它看起来像这样:map <silent> <Leader>y "9y:call system('YourCommand', @")<CR>主要的重点是system()函数接受第二个参数,该参数被写入程序的标准输入中,因此避免了所有转义问题。 - Tim Siegel
1
@TimSmith 你是对的,但是 @" 不是最好的选择。请看更新后的答案。 - ZyX

2

@matias的解决方案对我来说不太适用,因为似乎shellescape会在每行末尾添加\

所以我使用sed来完成,效果非常好!

"dump selected lines
function! DumpLines() range
  echo system('sed -n '.a:firstline.','.a:lastline.'p '.expand('%'))
endfunction

com! -range=% -nargs=0 Dump :<line1>,<line2>call DumpLines()

2
一种实现它的命令是:
  1. 复制你所需的内容
  2. 进入命令模式,使用:
  3. 在命令行中输入!,并粘贴你刚才复制的内容,可以使用<Ctrl> r "来粘贴
因此,命令如下:y : ! <Ctrl> r "

1

另一个答案:

function Pastebin() range
    let savedreg=@"
    silent execute a:firstline.",".a:lastline."yank"
    python import vim, subprocess
    python p=subprocess.Popen(["pastebin"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    python p.stdin.write(vim.eval('@"'))
    let @"=savedreg
    python p.stdin.close()
    python retstatus=p.poll()
    python print p.stdout.read()
endfunction

需要Python支持。就像使用Matias的函数一样使用它。


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