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

How do I run a shell command on a range of lines in normal mode and replace them with the output?

Answer

!{motion}{cmd}<CR>

Explanation

In normal mode, !{motion} sends the lines covered by the motion to a shell command's stdin and replaces them with stdout. Combined with !!{cmd}<CR> (which targets just the current line), this lets you apply any Unix filter to any portion of your buffer as a direct text transformation—no visual selection required.

How it works

!{motion}{command}<CR>
  • ! triggers the filter operator — Vim prompts for a shell command
  • {motion} defines the range (e.g., ip for inner paragraph, G for to end of file, 5j for 5 lines down)
  • {command} is any shell program that reads stdin and writes stdout
  • <CR> confirms and runs the filter

!!{command}<CR> is the shorthand that filters only the current line.

Example

Sort a list in place. Place the cursor inside an unordered list and run:

!ipsort<CR>

Before:

banana
apple
cherry

After:

apple
banana
cherry

Or right-align a column of numbers with awk on the current line:

!!awk '{printf "%10s\n", $0}'<CR>

Tips

  • !Gsort<CR> sorts everything from the cursor to end of file
  • !ipcolumn -t<CR> aligns tabular data in the inner paragraph
  • Chain filters with pipes: !ipsort | uniq<CR>
  • The entire filtered region is one undoable action — press u to restore the original
  • For visual selection filtering use !{cmd}<CR> after making a visual selection; Vim pre-fills :'<,'>!

Next

How do I filter the output of a Vim command to show only lines matching a pattern?