How to delete every other line in Vim?

Vim

Vim 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 regex fff (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. The g 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbrazhView Question on Stackoverflow
Solution 1 - Vimib.View Answer on Stackoverflow
Solution 2 - VimruiView Answer on Stackoverflow
Solution 3 - VimTadhgView Answer on Stackoverflow
Solution 4 - VimRaoul SupercopterView Answer on Stackoverflow
Solution 5 - VimFortegaView Answer on Stackoverflow
Solution 6 - VimslimView Answer on Stackoverflow
Solution 7 - VimMichael Krelin - hackerView Answer on Stackoverflow
Solution 8 - VimDaniel HershcovichView Answer on Stackoverflow
Solution 9 - VimqzrView Answer on Stackoverflow
Solution 10 - Vimkartik kailasView Answer on Stackoverflow
Solution 11 - VimwdogView Answer on Stackoverflow
Solution 12 - VimasdminView Answer on Stackoverflow