How do I pipe visually selected lines through an external shell command and replace them with the output?
Answer
:'<,'>!{cmd}
Explanation
Pressing ! while a visual selection is active drops to the command line with :'<,'>! pre-filled. You type a shell command, press <CR>, and Vim pipes the selected lines to the command's stdin—replacing the selection in the buffer with stdout. Any Unix filter (sort, uniq, column, awk, sed, python3 -) can be applied directly to buffer text without leaving Vim.
How it works
- Visually select one or more lines (
Vfor linewise,<C-v>for block) - Press
!— Vim enters the command line with:'<,'>! - Type the external command and press
<CR> - Vim pipes the selection to stdin and replaces it with stdout
The original content is overwritten; use u to undo.
Example
Given these unsorted lines selected with Vj:
banana
apple
cherry
Type !sort<CR>:
apple
banana
cherry
Or align a block of space-delimited columns by selecting them and running !column -t:
name age city
alice 30 NY
bob 25 LA
Tips
- Chain commands with pipes:
!sort | uniq -c | sort -rn<CR> !in normal mode (without a visual selection) uses a motion:!ip sort<CR>filters the inner paragraph!!{cmd}<CR>is the shorthand for filtering only the current line- The change is a single undoable action —
urestores the original lines