在Vim中搜索和替换特定行

140
我可以使用
:5,12s/foo/bar/g

在第5行和第12行之间搜索foo并将其替换为bar。我该如何只在第5行和第12行(而不是它们之间的行)进行替换?
5个回答

107

Vim有特殊的正则表达式原子,用于匹配特定的行、列等;你可以使用它们(可能是在范围之外)来限制匹配:

Vim具有特殊的正则表达式原子,可在特定的行、列等位置进行匹配;您可以使用它们(可能还要加上范围),以限制匹配:

:5,12s/\(\%5l\|\%12l\)foo/bar/g

请参见:help /\%l


9
比我预期的更复杂,但完美地回答了我的问题。谢谢! - pfnuesel

73

你可以在第五行进行替换,然后在第12行以最小的努力重复它:

:5s/foo/bar
:12&

正如Ingo所指出的那样,:&会忽略你的标记。由于您正在使用/g,因此正确的命令应该是:&&

就像Ingo指出的那样,:&会忽略你的标志。因为你使用了/g,所以正确的命令应该是:&&

:5s/foo/bar/g
:12&&

请参见:help :&及其相关命令。


11
赞成将晦涩难懂的符号 :& 利用起来。如果有标志 (s/../../g),就必须使用 :&&,不过... - Ingo Karkat
10
@IngoKarkat,公平地说,我认为\(\%5l\|\%12l\):&更晦涩难懂。 - doubleDown
“:&” 一点都不难理解。也许你可以阅读一些 Vim 的文档。 - undefined
@NeilG,Ingo有着丰富的经验和卓越的记录,他真的不是你需要推向文档的那种人。:&当然有文档记录,但在普通的Medium文章或YouTube视频中很少提到,遗憾的是,除非被迫,vimmers很少会超越这些内容。它甚至在Vim自己的介绍材料中都没有提到。从这个意义上说,:&绝对值得被称为“晦涩”。 - undefined
考虑到这样的记录,我不确定为什么他会将:&标记为晦涩。这在一定程度上是基于个人经验,但是语法的简洁性,以及该功能仅由一个字符提供,从客观上来看,这并不适合被列为“晦涩”列表中的内容。正如@doubleDown在他的评论中温和但坚定地指出的那样。我认为英戈在这件事上显然是错的。我不会对Medium的帖子抱有任何期望,更不用说任何视频了!当代科技博客中没有什么值得一提的质量。我回想起更久远的时光。我看着世界中的智慧渐渐流失。 - undefined
“:&”对我来说并不难以理解,因为我学习Vim时,是通过用户手册以及其中的“changes.txt”等资料来系统地学习的。我猜Ingo的学习过程也类似,你的情况可能也是如此。对于我们来说,这些东西并不难以理解:它们都有相对清晰的文档说明,并且在适当的时候我们会使用或建议使用它们。但这只是我们的情况,我们只是少数派。很多Vim用户可悲地并不关心这些,他们从博客、视频、推特等等获取所有的“知识”。对于他们来说,“:&”就是晦涩难懂的。 - undefined

24
你可以在结尾处加上 c ,这样每次匹配时都会要求确认。
:5,12s/foo/bar/gc

1
如果第5行到第12行之间有很多匹配项(请记住正则表达式中使用了“g”标志),那么这将成为一场噩梦。 - doubleDown
4
@doubleDown 这并不是一种通用解决方案(在有许多可能的候选项的情况下),但在大多数情况下,你真的认为按下 n 5 或 6 次比将 \(\%5l\|\%12l\) 添加到替换语句中更费力吗? - Dean
我觉得这很有用,我想要改变每隔一行,这比我最终所做的要快。 - tiktak

12
有趣的问题。看起来只有范围选择而没有多行选择:http://vim.wikia.com/wiki/Ranges。但是,如果第5行和第12行有特殊内容,您可以使用:g操作符。如果您的文件如下所示(仅供参考的数字):
 1     line one
 2     line one
 3     line one
 4     line one
 5     enil one
 6     line one
 7     line one
 8     line one
 9     line one
10     line one
11     line one
12     enil one

你想在出现enil而不是line的行中用eno替换one

并且您希望在出现enil而不是line的行中用eno替换one

:g/enil/s/one/eno/

6
这实际上假设了很多。 - doubleDown

2
你可以使用 ed 这个文本编辑器,他有类似于vi和vim的命令。它很可能比vi和vim更早出现。
在脚本中(使用here document处理输入直到EndCommand为止),它看起来应该像这样:
ed file <<EndCommands
    5
    s/foo/bar/g
    7
    s/foo/bar/g
    wq
EndCommands

显然,ed命令也可以在命令行上使用。

3
我不认为相比于Vim,它有什么优势。 - Bernhard
1
并且在Vim中也可以做到同样的事情;数字实际上可以放在 :s 前面,但仍然存在 :s 命令的重复(而 romainl 的解决方案避免了这种情况)。 - Ingo Karkat
我的观点是用户可能想选择超过两行进行编辑。在这种情况下,非交互式方法可能会很有用 - 这在我所知的vim中是无法实现的。 - suspectus
1
哦,Vim可以做到这一点(例如在“Ex”模式下),但你说得对,另一个工具应该优先于交互式编辑器。我的首选是sed... - Ingo Karkat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接