vimtricks.wiki Concise Vim tricks, one at a time.

How do I filter a range of text through an external shell command in Vim?

Answer

!{motion} {cmd}

Explanation

The ! operator passes text selected by a motion through an external shell command, replacing it with the command's output. This is one of Vim's most powerful features for leveraging Unix tools — sort lines, format code, decode base64, or run any pipeline without leaving the editor.

How it works

  • ! is the filter operator, similar to d (delete) or y (yank) — it takes a motion
  • {motion} selects the range: ip (inner paragraph), G (to end of file), 5j (5 lines down), etc.
  • {cmd} is any shell command that reads from stdin and writes to stdout
  • Vim replaces the selected text with the command's stdout

You can also use it from Ex mode with a range:

:%!sort -u
:1,10!column -t
:'<,'>!python3 -c 'import sys; print(sys.stdin.read().upper())'

Example

With the cursor inside this paragraph:

banana
apple
cherry

Typing !ipsort (then <CR>) produces:

apple
banana
cherry

Tips

  • !!{cmd} filters just the current line (e.g. !!date replaces the line with today's date)
  • !G{cmd} filters from cursor to end of file
  • =% works similarly but uses Vim's built-in equalprg — set equalprg=jq . to auto-format JSON with =ip
  • The shell command must be idempotent if you want to re-run it safely

Next

How do I refer to the matched text in a Vim substitution replacement?