以“ x”开头的重复行,用“ y”替换重复项中的“ x”?


9

我有一个具有以下模式的文件:

foo 111
baz
foo 222
baz
foo 333
baz

需要变成

foo 111
bar 111
baz
foo 222
bar 222
baz
foo 333
bar 333
baz

因此,请复制以开头的所有行foo,并仅foo在重复项中进行更改,但保留其余行(每种情况下都不同)。这个怎么做?


如果您对正则表达式不是一无所知,那么宏就可以了。在像这样的简单情况下并没有多大关系,但是如果您有一些复杂的东西,这是一个非常有效的选择。
PhilippFrank

Answers:


19

干得好:

:g/foo/t.|s//bar

分解:

:g/foo/    " start a global command applied on all lines matching 'foo'
t.         " duplicate the current line (the cursor is now on the new line)
|          " chain a new command
s//bar     " substitute the last searched element with 'bar'

由于该g命令将更新搜索模式,因此您可以在替换命令中省略要替换的模式。(参考::h :g,搜索search pattern)。


旧版本:

:g/foo/norm! yyp:s/foo/bar^M

分解:

:g            start a global command
/foo/         apply only on lines having 'foo'
norm!         execute a normal command
yyp           duplicate the line
:s//bar       replace foo with bar on the line (the duplicated one)
^M            add enter to execute the substitution

要插入^M印刷机Ctrl+venter

注意:在了解该t命令之前,我最初想出的是“旧”版本。我将保留它,但我不建议您使用它。第一个是更简洁明了的。


解决后,“简单版本”完美运行。但是,第一个版本导致重复的行仍以foo....
LB7979 '16

奇怪,您^M按照我的解释进入了吗?
nobe4 '16

我不好,读得不好。第一个解决方案也可以!
LB7979 '16

我不知道您为什么要麻烦所有复杂的版本。更简单的版本是...更简单。;)(更不用说符合POSIX了。)为什么不放在首位呢?
通配符

1
最初我想出了第一个版本,这对我来说很自然,因为当时我还不了解t,然后添加了第二个版本。我会改变顺序,你是对的。第一个是POSIX怎么样?
nobe4 '16

1

我一直在做这样的事情,只是做类似的事情%s/^foo \(.*\)/foo \1\rbar \1/(部分是因为我也做过很多类似的任务,这些任务无法通过复制功能变成聪明的东西,并且\(.*\)现在已经成为我肌肉记忆的一部分)。

我怀疑它与POSIX不兼容(不适用于其他vi克隆),但是使用^MC-VReturn)代替\r似乎可以在大多数其他vi克隆上使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.