Skip to content

/commands/vim/vim-delete-lines-matching-pattern

Vim :g/pattern/d: delete all lines matching a pattern

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · VIM - Vi IMproved 9.2 (2026 Feb 14updated
tool
Vim / Neovim
versions
Vim 8.x, Vim 9.x, Neovim
os
linux, macos, windows

In Vim, :g/pattern/d deletes every line that matches pattern, and :g!/pattern/d (or :v/pattern/d) deletes every line that does not match it. :g (global) first marks all matching lines, then runs the command after the pattern, here d (delete), on each of them. u undoes the whole operation at once.

Examples

Run in Vim's batch mode on a sample file; in the editor, type the same commands after :.

bash
printf 'keep 1\n# comment\nkeep 2\n\nDEBUG noise\nkeep 3\n' > app.conf
cp app.conf a.conf; vim -Nu NONE -i NONE -es -c 'g/^#/d' -c 'wq' a.conf
echo '--- :g/^#/d'; cat a.conf
cp app.conf b.conf; vim -Nu NONE -i NONE -es -c 'g/^\s*$/d' -c 'wq' b.conf
echo '--- :g/^\s*$/d'; cat b.conf
cp app.conf c.conf; vim -Nu NONE -i NONE -es -c 'v/keep/d' -c 'wq' c.conf
echo '--- :v/keep/d'; cat c.conf
cp app.conf d.conf; vim -Nu NONE -i NONE -es -c 'g/\cdebug/d' -c 'wq' d.conf
echo '--- :g/\cdebug/d'; cat d.conf

Output

--- :g/^#/d
keep 1
keep 2

DEBUG noise
keep 3
--- :g/^\s*$/d
keep 1
# comment
keep 2
DEBUG noise
keep 3
--- :v/keep/d
keep 1
keep 2
keep 3
--- :g/\cdebug/d
keep 1
# comment
keep 2

keep 3

Variations

CommandEffect
:g/pattern/dDelete lines that match
:g!/pattern/d or :v/pattern/dDelete lines that do not match
:g/^\s*$/dDelete empty and whitespace-only lines
:g/\cerror/dCase-insensitive match (\c anywhere in the pattern)
:10,50g/pattern/dOnly within lines 10 to 50
:g/pattern/d _Delete into the black hole register, keeping the unnamed register
:g/pattern/m$Move matching lines to the end of the file instead
:g/pattern/y AAppend matching lines to register a (clear it first with qaq)

Patterns with slashes

Any single-byte character other than a letter, \, ", | or ! can delimit the pattern, so paths need no escaping:

vim
:g#/usr/local#d

How :g works

:g runs in two passes. First it marks every line in the range (the whole file by default) that matches the pattern. Then it goes to each marked line in turn and runs the command with that line as the current line. Because lines are marked before anything is deleted, deleting one line does not make :g skip the next one, which is a common problem with hand-written loops. The command after the pattern can be any Ex command and can carry its own range relative to the matched line, so .,+1d deletes the matching line and the one after it:

bash
printf 'start\nERROR disk full\n  at line 3\nok\nERROR timeout\n  at line 9\nend\n' > log.txt
cp log.txt a.txt; vim -Nu NONE -i NONE -es -c 'g/^ERROR/.,+1d' -c 'wq' a.txt
echo '--- :g/^ERROR/.,+1d'; cat a.txt
vim -Nu NONE -i NONE -es -c 'redir! > msg.txt' -c 'g/zzz/d' -c 'redir END' -c 'qa!' log.txt
echo '--- :g/zzz/d on a file without zzz'; tr -d '\r' < msg.txt | grep -v '^$'

Output

--- :g/^ERROR/.,+1d
start
ok
end
--- :g/zzz/d on a file without zzz
Pattern not found: zzz

When nothing matches, Vim prints Pattern not found: followed by the pattern and changes nothing. When more lines than the report option (default 2) are deleted, it reports the count, such as 3 fewer lines.

Pattern syntax to remember

Vim patterns are not PCRE. In the default magic mode, \| is alternation, \( \) group, \+ and \= are the one-or-more and optional quantifiers, and \{n,m} is a counted repeat. Starting the pattern with \v (very magic) makes those characters special without backslashes, closer to other regex flavours. \c makes one search case-insensitive and \C case-sensitive, regardless of ignorecase. To reuse the last search, leave the pattern empty: after /TODO, :g//d deletes every line matching TODO.

Outside Vim

For files you do not want to open, sed '/pattern/d' file and grep -v 'pattern' file give the same result from the shell; see sed delete lines matching a pattern. Inside Vim, :g keeps undo history and works on the buffer you are editing, including unsaved changes. To change the matching lines instead of deleting them, combine :g with :s, as in Vim search and replace.

FAQ

How do I undo :g/pattern/d?

Press u once in Normal mode. Vim records the whole :g command as one change, however many lines it deleted.

How do I delete lines that contain either of two words?

Use alternation in the pattern, :g/foo\|bar/d. In Vim's default magic mode the | must be escaped; with very magic, :g/\v(foo|bar)/d, it does not.

How do I delete matching lines without overwriting what I yanked?

Delete into the black hole register with :g/pattern/d _. The unnamed register and the numbered registers stay as they were.

Sources