How to delete every other line in Vim?

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?

50166 次浏览

您可以为此使用宏。

  • 启动命令模式。
  • gg转到文件的开头。
  • Press qq.
  • 单击向下箭头,然后按 dd
  • q
  • 10000@q

PS: 要进入命令模式,只需按几次 Escape 即可。

来自 VIM 邮件存档:

: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,...)

你总是可以使用 shell 命令,这意味着你可以使用任何你喜欢的脚本语言:

:%!perl -nle 'print if $. % 2'

(或者使用“除非”代替“如果”,这取决于您想要哪一行)

:%!awk -- '++c\%2'

或者

:%!awk -- 'c++\%2'

取决于你想淘汰哪一半。

你可以像下面这样使用 Vim 自己的搜索和替换功能: 将光标放在第一行,然后在普通模式下键入:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • .,/fff/是替换的范围。它的意思是“从这一行到匹配正则表达式 fff的那一行(在本例中是最后一行)”。
  • s///是替代命令。它查找正则表达式,并用字符串替换每次出现的正则表达式。最后的 g意味着只要正则表达式不断被找到,就要重复替换操作。
  • 正则表达式 \n.*\(\n.*\)匹配一个换行符,然后是一整行(.*匹配除换行符之外的任意数量的字符) ,然后是另一个换行符和另一个换行符。括号 \(\)会记录其中的表达式,所以我们可以稍后使用 \1使用它。
  • \1插入分组的换行符和它后面的行,因为我们不希望下一行也消失-我们只希望替换机制通过它,所以我们不会在下一个替换中删除它。

通过这种方式,您可以控制希望删除操作发生的范围,并且不必使用任何外部工具。

:map ^o ddj^o
^o

这里 ^ 代表 CTRL。 Recursive macro to delete a line every two line. Choose well your first line and it's done.

我们可以使用 :normal(或 :norm)命令来执行 jdd正常模式命令:

:%norm jdd

来源: zzapper 的 最佳 Vim 提示页面。

An elegant (and efficient) way to accomplish the task is to invoke the :delete命令(参见 :help :d)表示 +行范围(.+1的缩写) 寻址当前行之后的行(参见 :help {address}) 每一行(见 :help /^)使用 :global命令(见 :help :g) :

:g/^/+d

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[:]将当前缓冲区中的所有行临时复制到 bb[::2]从缓冲区获取每两行代码,并将其分配给整个当前缓冲区 cb[:]。因为缓冲区对象似乎不支持扩展的片语法,所以有必要复制到 b

这可能不是“ vim 方式”,但如果您了解 python,可能会更容易记住。

解决方案

你可以试试这个

:1,$-1g/^/+1d

编辑

我会尽量说得更清楚(两部分)

第一部分选择范围(:from,to)
第二部分动作(d删除)

  • 从第一行到最后一行的范围(:1,$-1)
  • Globaly (g) delete (+1d)下一行

您可以尝试移动到您的文件的第一行,并执行 :+1d,您将看到下一行消失

我知道有点泥泞,但是很有活力,很有效

To delete odd lines (1, 3, 5, …):

:%s/\(.*\)\n\(.*\)\n/\2\r/g

删除偶数行(2,4,6,...) :

:%s/\(.*\)\n.*\n/\1\r/g

搜索文本(构成第一行) ,然后是一个新的行字符和更多的文本(构成第二行) ,接着是另一个新的行字符,并用第一个匹配(奇数行)或第二个匹配(偶数行)替换上面的内容,然后返回回车符。

调用 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

Responses to comments on another answer on this question (I can't comment because stack overflow requires reputation, it's so bad)

Https://stackoverflow.com/a/8334936/16603562

我们可以使用 :normal(或 :norm)命令来执行 jdd正常模式命令:

:%norm jdd

来源: zzapper 的 最佳 Vim 提示页面。


This answer doesn't get enough attention, possibly because of the lack of explanation both here and on the linked, messy, cheat sheet. the norm command runs the normal mode commands equivalent to the letters that follow it. So here it is running j to move down a line, and dd to delete it. This is generalizable to the Xth line by adding more 'j's in this case. – @ imoatama 2014年5月13日

这不起作用(试试看) ,但是你可以删除一切 但是的第 Xth 行添加更多的 dd(或 2dd,取代2与 X-1。)或者使用 g:g/^/+d2的顶部答案(再次用 X-1代替2)或者只使用宏或 sed,它们也可以完成原来的目标,即为 X > 2删除每个 Xth 行。

正如@Lambart 所说,

% 是1,$的简写(从第1行到结束执行以下命令)- 兰巴特 Jul 29, 2014

So if you do %norm jjdd, it will start the counter at line 1, then go to line 3 and delete it, but then it will go to line 2 and then go to line 4 and delete it, etc. This results deleting every odd line except the first line, not every third line.


我感兴趣的是,如果你想删除奇数行,为什么% normddj 不工作。- @ Cyker 2018年8月19日

这太让人困惑了。我的猜测是,基于大量的测试,原来的 %norm jdd工作是因为当命令中的某个命令出现故障时,它就会停止: 如果你在结束时执行 jdd,它就会执行 j,然后停止,因为它不能超过结束。但是,如果执行 ddj,它会先删除,然后停止。但这并不能阻止 %norm,它只能阻止 %norm内的每一行。

此外,计数器从1到原来的行号,它不会更新它。(这是有意义的,因为如果它更新了,您可以执行 :%norm p和无限循环。)如果计数器越过当前文件的最后一行,它就会转到最后一行。所以它删除了所有的行。

因此,要删除每一个奇数行而不是偶数行,可以执行 %norm jkddj。如果是在最后,它什么也不做,因为 j是在开头,但如果不是,它删除当前的行号。但是在运行命令之前删除第一行: dd 或者预先添加 d (:d|%norm jdd)会更容易。字数相同,但更直观。

(顺便说一下,这是在 Neovim 测试,它可能是相同的 Vim,但我没有尝试)