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

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

我当然可以这样执行:

:!scriptname

但是,是否有可能避免写脚本名称,以及如何在分割窗口中获得输出,而不是仅仅在屏幕底部?

74470 次浏览

There is the make command. It runs the command set in the makeprg option. Use % as a placeholder for the current file name. For example, if you were editing a python script:

:set makeprg=python\ %

Yes, you need to escape the space. After this you can simply run:

:make

If you wish, you can set the autowrite option and it will save automatically before running the makeprg:

:set autowrite

This solves the execute part. Don't know any way of getting that output into a split window that doesn't involve redirection to file.

To access the current buffer's filename, use %. To get it into a variable you can use the expand() function. To open a new window with a new buffer, use :new or :vnew. To pipe the output from a command into the current buffer, use :.! . Putting it all together:

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

obviously replacing ruby with whatever command you want. I used execute so I could surround the filename with quotation marks, so it'll work if the filename has spaces in it.

I use a slightly more intrusive mechanism through maps:

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

Just makes it so I don't have to save, then go. Just go.

For Shell script I've used

:set makeprg=%


:make

Vim has ! ("bang") command which executes shell command directly from VIM window. Moreover it allows launching sequence of commands that are connected with pipe and read stdout.

For example:

! node %

is equivalent to opening command prompt window and launching commands:

cd my_current_directory
node my_current_file

See "Vim tips: Working with external commands" for details.

I have a shortcut for that in my 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>

This writes the current buffer, makes the current file executable (unix only), executes it (unix only) and redirects the output to .tmp.xyz, then creates a new tab, reads the file and then deletes it.

Breaking it down:

: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

You can use vim's plugin bexec. To my knowledge the latest version is 0.5.

Then:

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

Inside vim itself while editing the .vba file do:

:so %

Some output will show up letting you know that bexec.vim has been written as well as documentation, etc..

Now, you can test it by opening your (whatever language script that has an #! interpreter working properly) in vim and run

:Bexec

Note: I wanted the split to be vertical rather than horizontal, so I did:

$ 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]

and changed the value of from "hor" to "ver"..

I know it's an old question, but I hope this can help someone out there. I have been running in the same issue while taking Coursera's Startup Engineering course where professor Palaji uses Emacs and I don't like Emacs..

Based on @SethKriticos and @Cyril answers I now use the following:

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>

Use F9 to setup the new window and F2 to execute your script and tee to your output file.

I also added the script name to the output file name, so that you can use this for multiple scripts at the same time.

@xorpaul

I was looking for this script (python/Windows) for quite some time. As there is no "tee" in Windows I changed it to:

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>

In your .vimrc you can paste this function

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

After that, in vim run command :shell python ~/p.py as example. And you will get the output in splitted window. + After changes in p.py as example you will run the same command again, this function will not create new window again, it will display the result in the previous(same) splitted window.

Vim 8 has an interactive terminal built in. To run the current bash script in a split pane:

:terminal bash %

or for short

:ter bash %

% expands to the current file name.

From :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.

Just use colon and exclamatory mark as shown below

:!< script_name>

I'd recommend the plugin quickrun. It's fast and simple to configure. Here's a little demonstration: enter image description here