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

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 u to 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.exe or PowerShell depending on your shell setting
  • Documented under :help :range!

Next

How do I run the same command across all windows, buffers, or tabs?