Vim Tips Wiki
(Remove html character entities)
(Undo revision 39239 by 88.98.37.186 (talk) avoiding reliance on external tools is not idiotic, nor are external tools easy to use in a platform-independant way in Vimscript)
Tag: sourceedit
 
(35 intermediate revisions by 13 users not shown)
Line 1: Line 1:
{{review}}
 
 
{{TipImported
 
{{TipImported
 
|id=467
 
|id=467
 
|previous=466
 
|previous=466
 
|next=468
 
|next=468
|created=April 30, 2003
+
|created=2003
 
|complexity=basic
 
|complexity=basic
|author=char
+
|author=
|version=5.7
+
|version=6.0
 
|rating=11/8
 
|rating=11/8
|category1=
+
|category1=Getting started
 
|category2=
 
|category2=
 
}}
 
}}
  +
This tip shows how to capture the output from running an external (or shell) command in Vim. Vim has many useful functions which can replace shell commands, such as {{help|prefix=no|strftime()}} or {{help|prefix=no|glob()}}, but sometimes only the shell command will do. See {{help|function-list}} for a list of Vim's built-in functions.
In Vim for *nix or cygwin, the command
 
   
  +
The results from running a shell command can be inserted into the current buffer with the <code>:read</code> command, or lines can be replaced in a buffer with a filter command, or Vim's <code>system()</code> function can be used like the backquote syntax (aka backtick) that many Unix shells provide to capture command output, which you can then use in a script or expression-register ({{help|id=quote=}}) to insert in the buffer or parse in some way.
:!cmd
 
   
  +
The following examples capture the output of the shell's <code>date</code> command. This is just an example: it is better to use Vim's <code>strftime()</code> function to get the [[Insert current date or time|date or time]].
displays the output inside vim windows, but for vim windows, the output is displayed in the console window.
 
   
  +
==Using :read==
To make the output displayed inside vim or gvim window, can use
 
  +
The <code>:read</code> command can insert a file or the result from running an external program into the current buffer. To run a program, preface the shell command with <code>!</code> (see {{help|:read!}}). For example,
  +
<pre>
  +
:read !date
  +
</pre>
   
  +
inserts the current date on a new line below the current line on most Unix-like systems (on Windows, use <code>:read !date /t</code>).
:echo system("command")
 
   
  +
If a line number is specified, the new text is inserted after that line. For example, <code>:12read !date</code> inserts the result after line 12, and <code>:$read !date</code> inserts the result after the last line. To insert the result before the first line, specify line 0 (<code>:0read !date</code>).
==References==
 
*{{help|system()}}
 
*{{help|:echo}}
 
   
  +
As a convenience, a user command (named <code>R</code>) can be defined to allow easy capture of output in a scratch buffer:
==Comments==
 
  +
<pre>
If you want, you can have the output of the command sent into your file by using the '!' mechanism a little further:
 
  +
:command! -nargs=* -complete=shellcmd R new | setlocal buftype=nofile bufhidden=hide noswapfile | r !<args>
  +
</pre>
   
  +
On a Unix-based system, the command <code>:R ls -l</code> would open a new window listing all files in the current directory, while on Windows commands such as <code>:R dir</code> or <code>:R dir /b /a-d</code> might be used.
:<range>!<command>
 
   
  +
The following example (for Unix) finds all files in or below the current directory that were modified in the last week (under 8 days); those files are searched for the text "vim", and all matching lines are listed in a new window:
This will send the lines in the range to the standard input of your command, and replace them with the standard output of the command (see help for details). Please remove _cba in my address to send me a note.
 
  +
<pre>
  +
:R find -mtime -8 | xargs grep vim
  +
</pre>
   
 
==Using system()==
----
 
  +
If you don't want the command output on a line by itself, or if you don't want it inserted, you can use the {{help|prefix=no|system()}} function. For example, to put the current date into a variable named <code>curdate</code>, which you can then use inside a script, use:
To read output of system commands into the actual file at filepos use ':r !<command>'.
 
  +
<pre>
<command> may be any shell-command, '%' is substituted with current file name,
 
  +
:let curdate=system('date')
e.g. ':r !ls -l %.bak' reads in the output of 'ls -l test.cpp.bak' while editing test.cpp.
 
  +
</pre>
   
  +
Using <code>system()</code> is the most flexible method as it allows a script to process the result before any output. For example, the function below appends the output of the command (if successfully executed) to the end of the current line. The script demonstrates these important concepts:
----
 
  +
*Use {{help|prefix=no|system()}} to capture the output of an external command in a script.
Try this.
 
  +
*Use {{help|prefix=no|shellescape()}} to escape any arguments to an external command to avoid passing possibly dangerous commands to the shell.
  +
*Use {{help|prefix=no|setline()}} to change text without moving the cursor.
   
  +
After sourcing the following script, press F8 to append the result from running the command to the current line. The <code>date -u</code> command, which works on Unix-based systems, outputs UTC time.
:echo system("dir ".expand("%"))
 
  +
<pre>
  +
nnoremap <F8> :call GetDate('')<CR>
  +
function! GetDate(format)
  +
let format = empty(a:format) ? '+%A %Y-%m-%d %H:%M UTC' : a:format
  +
let cmd = '/bin/date -u ' . shellescape(format)
  +
let result = substitute(system(cmd), '[\]\|[[:cntrl:]]', '', 'g')
  +
" Append space + result to current line without moving cursor.
  +
call setline(line('.'), getline('.') . ' ' . result)
  +
endfunction
  +
</pre>
   
  +
Using <code>strftime()</code> as explained at [[Insert current date or time|date or time]] is a better option for capturing timestamps. For example, the following command provides a mapping to append a tab character and the local time to the current line when F5 is pressed:
----
 
  +
<pre>
  +
nnoremap <F5> m'A<C-R>="\t".strftime('%Y-%m-%d %H:%M')<CR><Esc>``
  +
</pre>
  +
  +
In the mapping, <code>A</code> (append) enters insert mode at the end of the current line. Ctrl-R followed by <code>=</code> inserts the expression register, which evaluates the following expression, finishing with <code>CR</code> (Enter). The expression is <code>"\t"</code> (tab character), concatenated with the <code>strftime()</code> result. The final <code>Esc</code> exits from insert mode. The initial <code>m'</code> sets the previous context mark, and the final <code>``</code> jumps to that location to restore the cursor position after the append.
  +
  +
==Using a filter command==
  +
A filter is a program which reads text from standard input, then processes the text, and sends the result to standard output. In Vim, a range of lines can be selected, then replaced with the output from running a filter (the selected lines are the input to the filter).
  +
  +
For example, the following text may appear in a file that is being edited:
  +
<pre>
  +
One,Two,Three,Four,Five
  +
arborist,apple,artichoke,ant,author
  +
branch,banana,broccoli,bee,book
  +
canopy,cherry,cabbage,cricket,codex
  +
</pre>
  +
  +
The following procedure uses the <code>cut</code> utility (available on many Unix-based systems) to replace each line with fields 2 to 3 inclusive:
  +
*On the first line, press V to start a visual selection.
  +
*Press j to move the cursor down until all wanted lines are selected.
  +
*Press ! (the command line will show :'<,'>! indicating that the selected range will be filtered).
  +
*Enter a command to be executed by the shell, such as <code>cut -f2-3 -d,</code> (select fields 2-3 using comma as a delimiter between fields).
  +
  +
Vim saves the selected lines to a temporary file, then runs the external command with the temporary file as input. The result from running the command replaces the selected lines. In this example, the result is:
  +
<pre>
  +
Two,Three
  +
apple,artichoke
  +
banana,broccoli
  +
cherry,cabbage
  +
</pre>
  +
  +
See [[Use filter commands to process text#Simple filter example|this example]] using Python, and see {{help|filter}}.
  +
  +
===Using a filter to replace a command with its output===
  +
You can use this feature to replace a command with its output. For example on Windows if the buffer contains
  +
<pre>
  +
ping -n 1 1.1.1.1
  +
ping -n 1 1.1.1.2
  +
ping -n 1 1.1.1.3
  +
ping -n 1 1.1.1.4
  +
ping -n 1 1.1.1.5
  +
</pre>
  +
and you issue the command <code>:%!cmd</code> the five lines will be replaced with the output of the five commands.
  +
  +
The same method can be used on Unix with appropriate changes (for bash you would issue the command <code>%!bash</code>, and in this example the ping command would be <code>ping -c 1</code>).
  +
  +
==Using backticks==
  +
Above it is mentioned that using <code>system()</code> is ''like'' using backtick expansion in many shells. It should be noted that Vim actually does support real backticks in some situations. See {{help|backtick-expansion}} for details. This means you can do things like:
  +
<pre>
  +
:new `date`
  +
</pre>
  +
  +
to open a new buffer with a name matching the current date. This even works on Windows! The :help does not make it clear, but this works using the cmd.exe shell:
  +
<pre>
  +
:new `date /t`
  +
</pre>
  +
  +
This also provides a way to use Vim expressions where expressions are not normally allowed. For example, rather than using:
  +
<pre>
  +
:exe 'e' filename_in_var
  +
</pre>
  +
  +
you can use:
  +
<pre>
  +
:e `=filename_in_var`
  +
</pre>
  +
  +
==See also==
  +
*[[VimTip1599|Display output of shell commands in new window]]
  +
*{{script|id=4224}} offers a way to execute a command cmd using ":echo system(cmd)", but tipping ":! cmd" (note the space). As a benefit you get completion for commands like for ":!", and you don't leave vim.
  +
 
==Comments==
  +
Comment from old tip which should be mentioned somewhere:
  +
<pre>
 
:echo system("dir ".expand("%"))
  +
</pre>
  +
Following are relevant:
  +
*[[VimTip2|2 Easy edit of files in the same directory]]
  +
*[[VimTip193|193 Insert current filename]]
  +
*[[VimTip311|311 Open the folder containing the currently open file]]
  +
*[[VimTip432|432 Putting the current file on the Windows clipboard]]
  +
*[[VimTip530|530 Get the name of the current file]]
  +
*[[VimTip600|600 Copy filename to clipboard]]
  +
*[[VimTip891|891 Copy parts of filename to clipboard]]
  +
*[[VimTip1055|1055 Faster directory browsing from command line]]
  +
[[User:JohnBeckett|JohnBeckett]] 05:28, April 18, 2011 (UTC)

Latest revision as of 14:59, 13 July 2016

Tip 467 Printable Monobook Previous Next

created 2003 · complexity basic · version 6.0


This tip shows how to capture the output from running an external (or shell) command in Vim. Vim has many useful functions which can replace shell commands, such as strftime() or glob(), but sometimes only the shell command will do. See :help function-list for a list of Vim's built-in functions.

The results from running a shell command can be inserted into the current buffer with the :read command, or lines can be replaced in a buffer with a filter command, or Vim's system() function can be used like the backquote syntax (aka backtick) that many Unix shells provide to capture command output, which you can then use in a script or expression-register (:help quote=) to insert in the buffer or parse in some way.

The following examples capture the output of the shell's date command. This is just an example: it is better to use Vim's strftime() function to get the date or time.

Using :read[]

The :read command can insert a file or the result from running an external program into the current buffer. To run a program, preface the shell command with ! (see :help :read!). For example,

:read !date

inserts the current date on a new line below the current line on most Unix-like systems (on Windows, use :read !date /t).

If a line number is specified, the new text is inserted after that line. For example, :12read !date inserts the result after line 12, and :$read !date inserts the result after the last line. To insert the result before the first line, specify line 0 (:0read !date).

As a convenience, a user command (named R) can be defined to allow easy capture of output in a scratch buffer:

:command! -nargs=* -complete=shellcmd R new | setlocal buftype=nofile bufhidden=hide noswapfile | r !<args>

On a Unix-based system, the command :R ls -l would open a new window listing all files in the current directory, while on Windows commands such as :R dir or :R dir /b /a-d might be used.

The following example (for Unix) finds all files in or below the current directory that were modified in the last week (under 8 days); those files are searched for the text "vim", and all matching lines are listed in a new window:

:R find -mtime -8 | xargs grep vim

Using system()[]

If you don't want the command output on a line by itself, or if you don't want it inserted, you can use the system() function. For example, to put the current date into a variable named curdate, which you can then use inside a script, use:

:let curdate=system('date')

Using system() is the most flexible method as it allows a script to process the result before any output. For example, the function below appends the output of the command (if successfully executed) to the end of the current line. The script demonstrates these important concepts:

  • Use system() to capture the output of an external command in a script.
  • Use shellescape() to escape any arguments to an external command to avoid passing possibly dangerous commands to the shell.
  • Use setline() to change text without moving the cursor.

After sourcing the following script, press F8 to append the result from running the command to the current line. The date -u command, which works on Unix-based systems, outputs UTC time.

nnoremap <F8> :call GetDate('')<CR>
function! GetDate(format)
  let format = empty(a:format) ? '+%A %Y-%m-%d %H:%M UTC' : a:format
  let cmd = '/bin/date -u ' . shellescape(format)
  let result = substitute(system(cmd), '[\]\|[[:cntrl:]]', '', 'g')
  " Append space + result to current line without moving cursor.
  call setline(line('.'), getline('.') . ' ' . result)
endfunction

Using strftime() as explained at date or time is a better option for capturing timestamps. For example, the following command provides a mapping to append a tab character and the local time to the current line when F5 is pressed:

nnoremap <F5> m'A<C-R>="\t".strftime('%Y-%m-%d %H:%M')<CR><Esc>``

In the mapping, A (append) enters insert mode at the end of the current line. Ctrl-R followed by = inserts the expression register, which evaluates the following expression, finishing with CR (Enter). The expression is "\t" (tab character), concatenated with the strftime() result. The final Esc exits from insert mode. The initial m' sets the previous context mark, and the final `` jumps to that location to restore the cursor position after the append.

Using a filter command[]

A filter is a program which reads text from standard input, then processes the text, and sends the result to standard output. In Vim, a range of lines can be selected, then replaced with the output from running a filter (the selected lines are the input to the filter).

For example, the following text may appear in a file that is being edited:

One,Two,Three,Four,Five
arborist,apple,artichoke,ant,author
branch,banana,broccoli,bee,book
canopy,cherry,cabbage,cricket,codex

The following procedure uses the cut utility (available on many Unix-based systems) to replace each line with fields 2 to 3 inclusive:

  • On the first line, press V to start a visual selection.
  • Press j to move the cursor down until all wanted lines are selected.
  • Press ! (the command line will show :'<,'>! indicating that the selected range will be filtered).
  • Enter a command to be executed by the shell, such as cut -f2-3 -d, (select fields 2-3 using comma as a delimiter between fields).

Vim saves the selected lines to a temporary file, then runs the external command with the temporary file as input. The result from running the command replaces the selected lines. In this example, the result is:

Two,Three
apple,artichoke
banana,broccoli
cherry,cabbage

See this example using Python, and see :help filter.

Using a filter to replace a command with its output[]

You can use this feature to replace a command with its output. For example on Windows if the buffer contains

ping -n 1 1.1.1.1
ping -n 1 1.1.1.2
ping -n 1 1.1.1.3
ping -n 1 1.1.1.4
ping -n 1 1.1.1.5

and you issue the command :%!cmd the five lines will be replaced with the output of the five commands.

The same method can be used on Unix with appropriate changes (for bash you would issue the command %!bash, and in this example the ping command would be ping -c 1).

Using backticks[]

Above it is mentioned that using system() is like using backtick expansion in many shells. It should be noted that Vim actually does support real backticks in some situations. See :help backtick-expansion for details. This means you can do things like:

:new `date`

to open a new buffer with a name matching the current date. This even works on Windows! The :help does not make it clear, but this works using the cmd.exe shell:

:new `date /t`

This also provides a way to use Vim expressions where expressions are not normally allowed. For example, rather than using:

:exe 'e' filename_in_var

you can use:

:e `=filename_in_var`

See also[]

Comments[]

Comment from old tip which should be mentioned somewhere:

:echo system("dir ".expand("%"))

Following are relevant:

JohnBeckett 05:28, April 18, 2011 (UTC)