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 tod(delete) ory(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.!!datereplaces the line with today's date)!G{cmd}filters from cursor to end of file=%works similarly but uses Vim's built-inequalprg— setequalprg=jq .to auto-format JSON with=ip- The shell command must be idempotent if you want to re-run it safely