删除除第一个模式之外的所有出现的模式

删除除第一个模式之外的所有出现的模式

我正在尝试清理代码生成器的输出。不幸的是它会生成多个导入:

import Foo
...
import Foo

幸运的是,生成的文本相对静态,尽管它经常重新生成,因此我希望有一种简单的方法可以删除它。

我发现如果他们在同一条线上我可以:sed 's/import Foo//2g'

但是我不知道足够的 sed 来让它只考虑所有行。

一个 hacky 解决方案是运行多个 sed...

sed 's/\n/<string I know doesn't appear>/g'
sed 's/import Foo//2g'
sed 's/<string I know doesn't appear>/\n'

但这样做感觉不对。有一个更好的方法吗?

答案1

sed '/^import Foo$/{x;/^$/!d;g;}'

工作原理:在与模式匹配的每一行上

  • x:将行与保留空间交换
  • /^$/!d:如果刚刚从保存空间获取的内容不为空,即。因为之前的匹配项存储在那里,所以删除该模式并前进到下一行
  • g:否则(即第一次通过)将保存的行复制回来。默认情况下会打印

答案2

使用 GNU 实现sed(您可能正在使用它,因为您已经使用了 GNUism 2g),您可以这样做:

sed '0,/import Foo/!{//d}' < file

import Foo这将删除除第一行之外的所有行。/^import Foo$/如果您只想删除符合以下条件的行,请将模式替换为正是 import Foo

您也可以awk在这里使用:

awk '!/import Foo/ || !n++' < file

答案3

如果您的sed版本允许,请尝试

sed -z 's/import Foo//2g' file

答案4

保持简单、可移植等,并且必须使用 awk:

$ cat file
import Foo
import Bar
import More
import Foo
import Stuff
import Bar

$ awk '!seen[$0]++' file
import Foo
import Bar
import More
import Stuff

或者,如果只是以您想要使其唯一的行开头import,并且输入中还有您不想触及的其他行:

$ cat file
import Foo
int 3;
import Bar
char 7;
import More
int 3;
import Foo
char 7;
import Stuff
whatever
import Bar
whatever

$ awk '!(/^import/ && seen[$0]++)' file
import Foo
int 3;
import Bar
char 7;
import More
int 3;
char 7;
import Stuff
whatever
whatever

相关内容