How do I filter the entire buffer (or a range of lines) through an external shell command?
Answer
:%!
Explanation
The ! operator pipes text through a shell command, replacing the selected lines with the command's output. Prefixing with % applies it to the entire buffer. This turns Vim into an integration point for any Unix tool — sorting, formatting, transforming — without leaving the editor.
How it works
%— the range meaning "all lines"!{cmd}— pass the range to{cmd}via stdin, replace it with stdout
So :%!sort sends all lines to sort and replaces the buffer with the sorted output.
Example
Format a JSON file in-place using jq:
:%!jq .
Before:
{"name":"alice","age":30}
After:
{
"name": "alice",
"age": 30
}
Other useful patterns:
:%!sort -u " sort and deduplicate lines
:%!column -t " align columns
:5,20!indent " run indent formatter on lines 5–20
:.!date " replace current line with today's date
Tips
- Use a visual selection then press
!to filter only the selected lines — Vim auto-fills:'<,'> - If the command fails or produces no output, Vim restores the original lines
:.!{cmd}filters only the current line;:1,.!{cmd}filters from line 1 to the cursor- Combine with
undo(u) if the result is not what you expected