如何执行我正在Vi(m)中编辑的文件


101

如何执行我正在Vi(m)中编辑的文件并在拆分窗口中获取输出(如在SciTE中)?

当然,我可以像这样执行它:

:!scriptname

但是是否可以避免编写脚本名称以及如何在拆分窗口而不是屏幕底部获取输出呢?


21
:!%将使您避免编写“脚本名”。下面的解决方案更好,但是我想我提一下这个,以防您决定:!%足够好。
考虑过

11
另外请注意,您可以使用%:p(而不是仅使用%)来引用当前文件的绝对路径。如果当前目录在其他位置,则可能有必要。
安迪

4
运行ruby脚本:!ruby%可以解决问题
Alexis Perrier

1
@andy:!%:p还解决了目录不在$ PATH中的问题
MayTheSForceBeWithYou 2015年

2
:!"%:p"应付空白。
OJFord

Answers:


109

make命令。它运行makeprg选项中的命令集。使用%作为当前文件名的占位符。例如,如果您正在编辑python脚本:

:set makeprg=python\ %

是的,您需要逃脱空间。之后,您可以简单地运行:

:make

如果需要,可以设置该autowrite选项,它将在运行以下命令之前自动保存makeprg

:set autowrite

这解决了执行部分。不知道有什么方法可以将输出输出到不涉及文件重定向的拆分窗口中。


5
实际上,您的解决方案确实将输出发送到拆分窗口。使用:copen开放运行产生的“错误列表” :make。在自己的窗口。不幸的是,要使输出正确格式化,errorformat必须对选项进行一些调整。否则,将假定输出为gcc输出的格式。
出色的编译器2009年

2
您该对“ finagling”错误格式感到确定。它看起来像我见过的一些perl代码...
R. Martinho Fernandes

1
该功能可用于vim的“ make”项目(赋予vim类似IDE的功能)。:let f=expand("%")|vnew|execute '.!ruby "' . f . '"'尽管布莱恩·卡珀(Brian Carper)的解决方案()看起来很神秘,但其功能完全符合问题作者的要求。
AjayKumarBasuthkar 2014年

29

要访问当前缓冲区的文件名,请使用%。要将其放入变量中,可以使用expand()函数。要使用新缓冲区打开新窗口,请使用:new:vnew。要将命令的输出通过管道传输到当前缓冲区,请使用:.!。放在一起:

:let f=expand("%")|vnew|execute '.!ruby "' . f . '"'

显然替换ruby为您想要的任何命令。我使用过,execute所以我可以用引号将文件名引起来,因此如果文件名中有空格,它将可以使用。


3
@baboonWorksFine使用 :command! R let f=expand("%")|vnew|execute '.!ruby "' . f . '"'它可以:R执行命令
xorpaul 2014年

即使使用在执行时需要用户输入的脚本,也可以运行该脚本吗?
ilstam

23

Vim具有!(“ bang”)命令,可直接从VIM窗口执行shell命令。此外,它允许启动与管道连接并读取标准输出的命令序列。

例如:

! node %

相当于打开命令提示符窗口并启动命令:

cd my_current_directory 
node my_current_file

有关详细信息,请参见“视频提示:使用外部命令”


11

我在vimrc中有一个快捷方式:

nmap <F6> :w<CR>:silent !chmod 755 %<CR>:silent !./% > .tmp.xyz<CR>
     \ :tabnew<CR>:r .tmp.xyz<CR>:silent !rm .tmp.xyz<CR>:redraw!<CR>

这将写入当前缓冲区,使当前文件可执行(仅适用于unix),执行该文件(仅适用于unix),然后将输出重定向到.tmp.xyz,然后创建一个新选项卡,读取该文件,然后将其删除。

分解:

:w<CR>                             write current buffer
:silent !chmod 755 %<CR>           make file executable
:silent !./% > .tmp.xyz<CR>        execute file, redirect output
:tabnew<CR>                        new tab
:r .tmp.xyz<CR>                    read file in new tab
:silent !rm .tmp.xyz<CR>           remove file
:redraw!<CR>                       in terminal mode, vim get scrambled
                                   this fixes it

2
我非常喜欢您的解决方案,经过一段时间的使用,我认为它可以改进。因此,这是我的看法::w<CR>:silent !chmod +x %:p<CR>:silent !%:p 2>&1 | tee ~/.vim/output<CR>:split ~/.vim/output<CR>:redraw!<CR>—这会将stdout和stderr都重定向到temp文件,并且在这样做之前,它将所有内容打印到stdout,因此,如果脚本需要很长时间才能运行,您实际上会看到它正在工作。另外,它与目录无关(按绝对路径打开文件时出现错误)。但是,它不会以交互方式运行脚本,而且我还没有找到一种方法来做到这一点。
Kirill G

1
fyi-在@Cyril的解决方案中,我必须转义管道符号:| -> \ |
mpettis


3

Vim 8内置有一个交互式终端。要在拆分窗格中运行当前的bash脚本,请执行以下操作:

:terminal bash %

或简称

:ter bash %

% 扩展为当前文件名。

来自:help terminal

The terminal feature is optional, use this to check if your Vim has it:
    echo has('terminal')
If the result is "1" you have it.

1

我通过地图使用一种更具侵入性的机制:

map ;e :w<CR>:exe ":!python " . getreg("%") . "" <CR>

做到这一点,这样我就不必保存,然后继续。去吧。


1
如果设置了自动写入选项,则可以运行:make并自动保存。
R. Martinho Fernandes 2009年

1

您可以使用vim的插件bexec。据我所知,最新版本是0.5。

然后:

$ mkdir -p ~/.vim/plugin
$ mv bexec-0.5.vba ~/.vim/plugin
$ vim ~/.vim/plugin/bexec-0.5.vba

编辑.vba文件时,在vim本身内部执行以下操作:

:so %

将会显示一些输出,让您知道已经编写了bexec.vim以及文档等。

现在,您可以通过在vim中打开您的(任何带有#!解释器的语言脚本)进行测试并运行

:Bexec 

注意:我希望拆分是垂直的,而不是水平的,所以我这样做了:

$ grep -i -n split ~/.vim/plugin/bexec.vim | grep -i hor
102:    let bexec_splitdir = "hor" " hor|ver
261:        exec {"ver":"vsp", "hor":"sp"}[g:bexec_splitdir]

并将值从“ hor”更改为“ ver”。

我知道这是一个老问题,但是我希望这可以帮助某个人。我参加Coursera的启动工程课程时遇到了同样的问题,Palaji教授使用Emacs,但我不喜欢Emacs。


您应该在本地.vimrc中更改与首选项相关的设置。bexec提供了“ let bexec_splitdir ='hor'”设置,该设置无需修改插件代码即可。
Saurabh Hirani 2014年

0

基于@SethKriticos和@Cyril的答案,我现在使用以下内容:

function! Setup_ExecNDisplay()
  execute "w"
  execute "silent !chmod +x %:p"
  let n=expand('%:t')
  execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
  " I prefer vsplit
  "execute "split ~/.vim/output_".n
  execute "vsplit ~/.vim/output_".n
  execute "redraw!"
  set autoread
endfunction

function! ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
  " I use set autoread
  "execute "1 . 'wincmd e'"
endfunction

:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>

使用F9设置新窗口,然后使用F2执行脚本并进入输出文件。

我还将脚本名称添加到了输出文件名中,以便您可以同时将其用于多个脚本。


0

在您.vimrc可以粘贴此功能

function! s:ExecuteInShell(command)
  let command = join(map(split(a:command), 'expand(v:val)'))
  let winnr = bufwinnr('^' . command . '$')
  silent! execute ':w'
  silent! execute  winnr < 0 ? 'vnew ' . fnameescape(command) : winnr . 'wincmd w'
  setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
  silent! execute 'silent %!'. command
  silent! redraw
  silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
  silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
  silent! execute 'wincmd w'
  " echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
cabbrev shell Shell

之后,以vim运行命令:shell python ~/p.py为例。您将在拆分窗口中获得输出。+在p.py示例中进行更改后,您将再次运行相同的命令,此函数将不会再次创建新窗口,它将在先前(相同)拆分的窗口中显示结果。


太棒了,谢谢!当再次写入缓冲区时,如何更改它以重新运行?
elzi '16

0

@xorpaul

我一直在寻找此脚本(python / Windows)一段时间。由于Windows中没有“ tee”,因此将其更改为:

function! Setup_ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent ! python % > d:\\temp\\output_".n ." 2>&1"
  execute "vsplit d:\\temp\\output_".n
  execute "redraw!"
  set autoread
endfunction

function! ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent ! python % > d:\\temp\\output_".n . " 2>&1"
endfunction

:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>

0

只需使用冒号和感叹号,如下所示

:!<脚本名称>


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.