How do I run a command on lines matching a pattern within blocks matching another pattern?
Answer
:g/outer/,/end/g/inner/
Explanation
The :global command accepts a range, which lets you scope its search to sections of the file rather than the entire buffer. Combining two :g commands — one to define a block range and one to filter within it — enables surgical multi-level filtering that a single :g cannot express.
How it works
:g/outer-pattern/,/end-pattern/g/inner-pattern/command
:g/outer/,/end/— for each match ofouter, treat the range from that line to the next match ofendas the target regiong/inner/command— within that region, runcommandon every line matchinginner
The outer :g iterates over starting lines; the inner g/inner/command treats the current block as a temporary sub-range.
Example
Given a log file where error details appear inside BEGIN/END blocks:
BEGIN section
INFO request received
ERROR disk full
WARN retrying
END section
BEGIN section
INFO success
END section
To delete all ERROR lines only within BEGIN/END blocks:
:g/^BEGIN/,/^END/g/^ ERROR/d
Result: only the ERROR disk full line is removed. Lines outside the blocks are untouched.
Tips
- Combine with
:v(inverse match) for exclusion::g/BEGIN/,/END/v/INFO/ddeletes non-INFO lines inside each block - The inner command can be anything:
:norm,:s,:y A(collect to register),:t$(copy to end) - Ranges can overlap — if
ENDdoes not appear, the range extends to end of file - Use
:g/BEGIN/,/END/s/foo/bar/gto substitute only inside blocks