Vim: `!!`


The vi term is cmdline-ranges, see :help cmdline-ranges, good youtube video that describes a lot of related ex commands and how these work

In command mode, you can hit !! twice, to bring up a prompt which will send the current line to some external command.

For example, if you write:

which docker-compose

and then on that line, type !!bash, it’ll send that to bash, and replace the current line with the output of that command.

/home/username/.local/bin/docker-compose

Could just as easily send some snippet of code to python or perl, or anything.

  • :.$ to run vim commands
  • :.! to run external commands

This doesn’t have to be on single lines though, you can do 6!! to send 6 lines to some external command.

As an example for vim commands, the keystrokes you’d have to do to write 5 lines to another file would be:

5!!<delete>$:w /tmp/output

the delete is to replace the ! (external vim command) to a $, which specifies a vim command.

The line would look like:

:.,.+4$:w /tmp/foo

The complicated .,.+4 is generated by vim when you do !!5, $:w /tmp/foo is the command I typed in.

I have a script called ix here which accepts some text as STDIN and makes an ix (pastebin), so I can do something like:

5!!ix -v (which becomes :.,.+4!ix -v)

.. which takes those 5 lines and uploads them to ix, copying a link to that paste to my clipboard, without ever leaving vim!

While not a feature in vi, in vim and neovim, this also works with visual mode, so say you had two commands:

date
cal

If you go into visual line mode (V) and select both lines, then hit !, the become

'<,'>! — which represents your selection

By sending that to bash:

<,'>!bash

Sat Mar 12 02:19:04 PM PST 2022
     March 2022
Su Mo Tu We Th Fr Sa
       1  2  3  4  5
 6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31