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

How do I pipe a range of lines through an external shell command and replace them with the output?

Answer

:{range}!{cmd}

Explanation

:!{cmd} with a range sends those lines as stdin to the shell command and replaces them with the command's stdout. This is Vim's filter mechanism for arbitrary line ranges — from a single line to the whole file — transforming text with any Unix tool without leaving Vim.

Syntax

:{range}!{command}

Common range shortcuts:

  • . — current line: :.!cmd
  • % — entire file: :%!cmd
  • '<,'> — visual selection (auto-filled on :)
  • 1,10 — lines 1–10
  • .,+4 — current line and next 4 lines

Examples

Sort the entire file:

:%!sort

Format JSON for the whole buffer:

:%!python3 -m json.tool

Base64-encode the current line:

:.!base64

Run a custom script on lines 5–20:

:5,20!./transform.py

Pretty-print XML in a selection:

:'<,'>!xmllint --format -

Tips

  • If the command fails or produces no output, Vim replaces the range with nothing — use u immediately to undo
  • ! in normal mode also works: !!cmd filters the current line; !{motion}cmd filters the motion's range
  • The command sees the exact bytes from the buffer, including any trailing newlines
  • This is how Vim integrates with the Unix philosophy: every tool that reads stdin and writes stdout becomes a buffer transformation

Next

How do I run a search and replace only within a visually selected region?