2016-07-28 79 views
0

我试图在文本文件中每次出现一个字符串,以取代使用awk替换每个第n次出现的图案

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

问题是要找到并替换每五分之一的“@”。

因为我需要它反复,在printing with sed or awk a line following a matching pattern建议的答案不会做这项工作。再次,我不只是在寻找一个匹配的地方,而是寻找其中的很多。

我有什么至今:

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

取代2日至5日次数(没有更多)。 (顺便说一句,我发现这里采用此解决方案: “Sed replace every nth occurrence” 最初,它是为了取代每秒occurence - 这确实。)

;第二:

awk -v p="@" -v n="5" '$0~p{i++}i==n{sub(/^@/, "\n#\[email protected]")}{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#\[email protected]"> 
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} 
} 

感谢您的帮助。

+0

你看过http://stackoverflow.com/a/17914105/1745001了吗?如果这不能提供答案,请编辑您的问题以包含简洁,可测试,样本输入和预期输出,我们可以为您提供帮助。 –

+0

谢谢,但提供的答案不能解决上述问题。编辑我的问题,使事情更清晰。 – jakr

回答

0

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

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

所以与支架更好的理解,你需要像((i % n) == 0)

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

是的,你是对的,我更新了答案。 – sozkul

+0

这正是我想要的 - 非常感谢,@sozkul! 你能解释一下它的魔力吗?正如我所看到的,它与刚才建议的“i == n”中的字符串“i%n == 0”不同。它究竟做了什么?没有真正理解。 – jakr

0

的表达,你可以一步完成拆分的awk容易。

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

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

+0

你应该提到这是gawk特定的,因为'RT'和输出重定向的非括号右侧。 –

+0

谢谢。你的方法听起来更好,但我没有得到任何结果文件(也没有错误信息)。使用gawk 4.1.3。 – jakr

0

相反在使用多个工具多个步骤这样做的,只是这样做:

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

未经检验的,因为你没有提供任何样品的输入/输出。

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

+0

谢谢。 Awk说: 1.当我在前面提到'close(out)'时,在字符串'out =“out”++ c'的等号处出现语法错误。 2.(FILENAME = in.bib FNR = 1)致命错误:> ist ein leerer字符串 其中的内容如下:带有“>”的重定向表达式是空字符串。 ? 我使用gawk 4.1.3。 – jakr

+0

您发错了复制/粘贴脚本,因为我发布的脚本**不会在任何awk中产生语法错误。如果你编辑你的问题以包含你运行的脚本和它产生的错误,我们可以帮你调试它。你现在与我们共享的输入使得这个问题变得简单得多,因为当记录被空行分隔时,awk有一个特定的RS使用,但是我不明白你为什么仍然把注意力放在'#'用awk记录下来,当你显示awk可以直接拆分文件时,准备稍后调用split。 –

+0

Hej非常感谢,@ ed-morton为您在这个问题上的不懈努力!我非常感谢。我没有说你做错了 - 我只是无法得到它的工作。这很可能是因为我没有深入了解awk编程,因为我不应该理解您的建议。我只是在非常非常基础的层面上理解它。因此,我仍然没有得到您的建议,因此我坚持使用csplit解决方案。这对我很有用,因为我可以处理它。这是我第一次接触到awk,我只是想让我的问题得到解决,即使在肮脏的方式。竖起大拇指! – jakr

相关问题