Working Code
You can run shell commands without leaving Vim:
:!ls ← list files in the current directory
:!python3 % ← run the current file with Python (% = current file)
:!node % ← run the current file with Node.js
You can also insert a command's output into the file:
:read !date ← insert current date/time below the cursor
:read !ls ← insert file listing below the cursor
And run a command across multiple lines at once:
:5,10d ← delete lines 5-10
:5,10s/foo/bar/g ← replace foo with bar on lines 5-10
:'<,'>norm I// ← prepend // to each line in the visual selection
Try It Yourself
Suppose you have this code. Open it in Vim and try the commands:
// TODO: implement login
const name = "dale";
const age = 30;
// TODO: add error handling
function greet() {
console.log("hello");
}
// TODO: write tests
function add(a, b) {
return a + b;
}
Run external commands:
:!wc -l % ← count lines in the current file
:!grep TODO % ← find lines containing TODO
Work with ranges:
:1,3d ← delete the first three lines
:%s/TODO/FIXME/g ← replace TODO with FIXME across the file
Practice :norm — apply to many lines at once:
After selecting lines with Visual mode, try:
Select lines with V → :norm I// ← prepend // as a comment
Select lines with V → :norm 0xx ← remove the leading // comment
Practice :g (global):
:g/TODO/d ← delete every line containing TODO
:g/^$/d ← delete every blank line
:v/function/d ← delete every line that does NOT contain function (:v is the inverse of :g)
"Why?"
The real power of command-line mode lies in range + command combinations.
:! is the bridge to the terminal. You can run code, check results, and even insert the output — all without leaving the editor. % is a special symbol meaning "the current file name."
Range specifications let you precisely target where the command applies:
| Range | Meaning |
|---|---|
5,10 | Lines 5-10 |
% | Entire file |
'<,'> | Current Visual selection |
. | Current line |
$ | Last line |
.,$ | From current line to end of file |
:norm runs a Normal-mode command across many lines. :norm I// means "on each line, run I// in Normal mode." You get repetitive editing without recording a macro.
:g/pattern/command is Vim's secret weapon. It runs a command on every line matching a pattern. In fact, the name grep itself comes from this command — global regular expression print.
Deep Dive
:g command cookbook
:g/console.log/d ← delete every console.log line
:g/^#/norm A. ← append a period to every Markdown heading
:g/^$/d ← delete all blank lines
:g/import/t$ ← copy every import line to the end of file
:v/return/d ← delete every line without return
:g/TODO/norm 0i[x] ← prepend [x] to every TODO line
The inverse of :g is :v (inVerse). :v/pattern/d deletes lines that do not match.
Sorting lines with :sort
:sort ← alphabetical sort of the whole file
:5,10sort ← sort only lines 5-10
:sort! ← reverse sort
:sort u ← sort and remove duplicates
:sort n ← numeric sort
Perfect for sorting CSS properties alphabetically or tidying up import statements.
Create a file with the content below and clean it up in Vim:
banana
apple
cherry
date
apple
elderberry
banana
:g/^$/dto remove every blank line.:sort uto sort and deduplicate.:%norm I-to prepend a Markdown list marker to every line.:read !dateto append the current date.
Target result:
- apple
- banana
- cherry
- date
- elderberry
(current date)
question: How do you run the current file with Python from inside Vim? answers:
question: What does :g/TODO/d do? answers:
question: How do you prepend // to every line in a Visual selection? answers: