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

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 of outer, treat the range from that line to the next match of end as the target region
  • g/inner/command — within that region, run command on every line matching inner

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/d deletes 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 END does not appear, the range extends to end of file
  • Use :g/BEGIN/,/END/s/foo/bar/g to substitute only inside blocks

Next

How do I center or right-align lines of text using Vim's built-in Ex commands?