How do I pass a range of lines through a shell command and replace them?
Answer
:{range}!command
Explanation
The :{range}!command syntax pipes the specified lines through an external shell command and replaces them with the output. This is one of Vim's most powerful Unix integration features — any command-line tool becomes an in-editor text transformer.
How it works
:.!command " Filter current line through command
:5,10!command " Filter lines 5-10 through command
:'<,'>!command " Filter visual selection through command
:%!command " Filter entire file through command
The selected lines become stdin for the command, and stdout replaces them.
Practical examples
" Sort lines 10-20
:10,20!sort
" Reverse a selected block
:'<,'>!tac
" Format selected JSON
:'<,'>!jq .
" Deduplicate lines
:'<,'>!sort -u
" Number the lines
:'<,'>!nl -ba
" Word-wrap a paragraph at 72 columns
:'<,'>!fmt -w 72
" Base64 encode selected text
:'<,'>!base64
" Calculate with bc
:.!bc
Normal mode operator
!!command " Filter current line (shorthand for :.!)
!ip command " Filter current paragraph
!G command " Filter from current line to end of file
Tips
- The command receives the lines as stdin and must produce output on stdout
- Use
uto undo if the result isn't what you expected - This is the "Unix philosophy" in action — compose small tools inside Vim
- Shell commands run with your current shell (
$SHELL) - On Windows, this uses
cmd.exeor PowerShell depending on yourshellsetting - Documented under
:help :range!