How to delete every other line in Vim?
VimVim Problem Overview
I would like to delete every other line from a Vim buffer, starting with the second one, i.e., lines 2, 4, 6, etc. For example, if the buffer’s contents is:
aaa
bbb
ccc
ddd
eee
fff
then, after the desired line removal, it should become:
aaa
ccc
eee
Which Vim commands can be used to automate this operation?
Vim Solutions
Solution 1 - Vim
An elegant (and efficient) way to accomplish the task is to invoke the
:delete
command (see :help :d
) for the +
line range (same as .+1
)
addressing the line following the current one (see :help {address}
), on
every line (see :help /^
) using the :global
command (see :help :g
):
:g/^/+d
Solution 2 - Vim
You can use a macro for this. Do the following.
- Start in command mode.
- Go to the beginning of the file by pressing
gg
. - Press
qq
. - Click arrow down and press
dd
after. - Press
q
. - Press
10000@q
PS: To go to command mode just press Escape a couple of times.
Solution 3 - Vim
We can use the :normal
(or :norm
) command to execute
the j
and dd
Normal-mode commands:
:%norm jdd
Source: the Best of Vim Tips page by zzapper.
Solution 4 - Vim
:map ^o ddj^o
^o
Here ^ stand for CTRL. Recursive macro to delete a line every two line. Choose well your first line and it's done.
Solution 5 - Vim
from vim mail archive:
:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile
(To be typed on one line on the vim command line, will delete row 1,3,5,7,...)
Solution 6 - Vim
You can always pipe though a shell command, which means you can use any scripting language you like:
:%!perl -nle 'print if $. % 2'
(or use "unless" instead of "if", depending on which lines you want)
Solution 7 - Vim
:%!awk -- '++c\%2'
alternatively
:%!awk -- 'c++\%2'
depending on which half you want to weed out.
Solution 8 - Vim
You can use Vim's own search and substitute capabilities like so: Put your cursor at the first line, and type in normal mode:
:.,/fff/s/\n.*\(\n.*\)/\1/g
- The
.,/fff/
is the range for the substitution. It means "from this line to the line that matches the regexfff
(in this case, the last line). s///
is the substitute command. It looks for a regex and replaces every occurrence of it with a string. Theg
at the end means to repeat the substitution as long as the regex keeps being found.- The regex
\n.*\(\n.*\)
matches a newline, then a whole line (.*
matches any number of characters except for a newline), then another newline and another line. The parentheses\(
and\)
cause the expression inside them to be recorded, so we can use it later using\1
. \1
inserts the grouped newline and the line after it back, because we don't want the next line gone too - we just want the substitution mechanism to pass by it so we don't delete it in the next replacement.
This way you can control the range in which you want the deletion to take place, and you don't have to use any external tool.
Solution 9 - Vim
As another approach you could also use python if your vim has support for it.
:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]
b = cb[:]
temporarily copies all lines in the current buffer to b
. b[::2]
gets every second line from the buffer and assigns it to the whole current buffer cb[:]
. The copy to b
is necessary since buffer objects don't seem to support extended slice syntax.
This is probably not the "vim way", but could be easier to remember if you know python.
Solution 10 - Vim
To delete odd lines (1, 3, 5, …):
:%s/\(.*\)\n\(.*\)\n/\2\r/g
To delete even lines (2, 4, 6, …):
:%s/\(.*\)\n.*\n/\1\r/g
Search for text (forms the first line) followed by a new line character and some more text (forms the second line) followed by another new line character and replace the above with either first match (odd line) or second match (even line) followed by carriage return.
Solution 11 - Vim
solution
you can try this in vim
:1,$-1g/^/+1d
#edit
I'll try to be more clear (two parts)
first part the selection range (:from,to
)
second part the action (d
delete)
- the range if from first line to the last but one line (
:1,$-1
) - globaly (
g
) delete (+1d
) next line
you can try to move to the first line of your file and execute :+1d
you will see the next line disappear
I know it is muddy, but it's vim and it works
Solution 12 - Vim
Invoke sed:
:% !sed -e '2~2 d'
^^^^ pipe file through a shell command
^^^^^^ the command is sed, and -e describes an expression as parameter
^^^^^ starting with the second line, delete every second line