How do I pipe a range of lines through an external command and replace them with the output?
Answer
!{motion}{command}
Explanation
The ! operator filters the text covered by a motion through an external shell command, replacing the original lines with the command's stdout. This turns Vim into a powerful text pipeline — you can sort, format, encode, or transform arbitrary ranges of text using any CLI tool without leaving the editor.
How it works
!initiates the filter operator and waits for a motion- The motion defines which lines to filter (e.g.,
5jfor the next 5 lines,ipfor the current paragraph,Gfor to the end of file) - After the motion, Vim drops to the command line with the range pre-filled; type your shell command and press
<CR> - The selected lines are sent to the command via stdin and replaced with its stdout
Example
To sort the next 5 lines alphabetically:
banana
apple
cherry
date
elderberry
With the cursor on banana, press !4jsort<CR>:
apple
banana
cherry
date
elderberry
Other useful combinations:
!ipsort -u " sort paragraph, remove duplicates
!ipcolumn -t " align paragraph as a table
!GBase64 " base64-encode from cursor to end of file (macOS)
Tips
- In Visual mode, press
!after a selection to filter just those lines !!is a shorthand to filter only the current line- The range form
:5,10!sortworks the same way from command-line mode - The original lines go to the unnamed register before being replaced, so
uundoes the filter