使用awk替换每个第n次出现的模式

时间:2016-07-28 12:56:45

标签: linux bash awk

我试图在文本文件中替换每个第n次出现的字符串。

背景: 我有一个巨大的bibtex文件(称为in.bib),包含以" @"开头的数百个条目。但每个条目都有不同的行数。我想写一个字符串(例如"#")就在每次(比如说)第6次出现" @"之前。所以,在第二步中,我可以使用 csplit 将大文件拆分为"#"到每个包含5个条目的文件中。

问题是找到并更换每五个" @"。

由于我需要反复printing with sed or awk a line following a matching pattern中建议的答案不会完成。同样,我不是只寻找一个匹配的地方,而是寻找其中许多地方。

到目前为止我所拥有的:

awk '/^@/ && v++%5 {sub(/^@/, "\n#\n@")} {print > "out.bib"}' in.bib

替换第2次直到第5次出现(并且不再有)。 (顺便说一下,我在这里找到并采用了这个解决方案:" Sed replace every nth occurrence"。最初,它意味着取代每一次出现 - 它确实如此。)

而且,第二:

awk -v p="@" -v n="5" '$0~p{i++}i==n{sub(/^@/, "\n#\n@")}{print > "out.bib"}' in.bib

完全取代了第五次出现而没有别的。 (从这里采用的解决方案:" Display only the n'th match of grep"

我需要(而且不能写)是一个循环。 for循环可以完成这项工作吗?类似的东西:

for (i = 1; i <= 200; i * 5)
   <find "@"> and <replace with "\n#\n@">
then print

我的材料看起来像这样:

@article{karamanic_jedno_2007,
    title = {Jedno Kosova, Dva Srbije},
    journal = {Ulaznica: Journal for Culture, Art and Social Issues},
    author = {Karamanic, Slobodan},
    year = {2007}
}

@inproceedings{blome_eigene_2008,
    title = {Das Eigene, das Andere und ihre Vermischung. Zur Rolle von Sexualität und Reproduktion im Rassendiskurs des 19. Jahrhunderts},
    comment = {Rest of lines snippet off here for usability -- as in following entries. All original entries may have a different amount of lines.}
}

@book{doring_inter-agency_2008,
    title = {Inter-agency coordination in United Nations peacebuilding}
}

@book{reckwitz_subjekt_2008,
    address = {Bielefeld},
    title = {Subjekt}
}

我想要的是每个第六个条目,如下所示:

#
@book{reckwitz_subjekt_2008,
    address = {Bielefeld},
    title = {Subjekt}
}

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

您的代码几乎是正确的,我修改了它。

要替换每第n次出现,您需要一个模块化表达式。

因此,为了更好地理解括号,您需要一个像((i % n) == 0)

这样的表达式
awk -v p="@" -v n="5" ' $0~p { i++ } ((i%n)==0) { sub(/^@/, "\n#\n@") }{ print }' in.bib > out.bib

答案 1 :(得分:0)

您可以轻松地在awk分步进行拆分。

awk -v RS='@' 'NR==1{next} (NR-1)%5==1{c++} {print RT $0 > FILENAME"."c}' file

将创建file.1,file.2等,每个记录包含5条记录,其中记录由分隔符@定义。

答案 2 :(得分:0)

不要使用多个工具在多个步骤中执行此操作,只需执行以下操作:

awk '/@/ && (++v%5)==1{out="out"++c} {print > out}' file

未经测试,因为您没有提供任何样本输入/输出。

如果您没有GNU awk且输入文件很大,则需要在close(out)之前添加out=...,以避免同时打开太多文件。