如何在满足特定条件时使用 awk 删除一组行

如何在满足特定条件时使用 awk 删除一组行

我用来awk删除文件中的重复项,问题是如果发现重复项,我想删除一组行,例如-

<p>
This is duplicate.
</p>
<p>
This is original.
</p>
<p>
This is duplicate.
</p>

我想把它改成——

<p>
This is duplicate.
</p>
<p>
This is original.
</p>

当一行重复时,删除上一行和下一行,任何帮助将不胜感激。

我目前正在使用-

awk -i inplace '!seen[$0]++' name_of_file

删除重复的行,但我无法弄清楚如何删除上一行和下一行。

答案1

我认为您真正想做的是删除重复的<p>...</p>分隔记录而不是单独的行。鉴于您发布的示例,这就是 GNU awk (您已经将其用于-i inplace)多字符 RS:

$ awk 'BEGIN{RS=ORS="</p>\n"} !seen[$0]++' file
<p>
This is duplicate.
</p>
<p>
This is original.
</p>

请注意,无论记录中有多少行,这都有效<p>...</p>,例如,给定此输入,其中重复记录是多行:

$ cat file
<p>
This
is
duplicate.
</p>
<p>
This is original.
</p>
<p>
This
is
duplicate.
</p>

该脚本仍然删除重复项:

$ awk 'BEGIN{RS=ORS="</p>\n"} !seen[$0]++' file
<p>
This
is
duplicate.
</p>
<p>
This is original.
</p>

答案2

awk不是解析xml/html数据的正确工具,输入格式稍有变化就会失败。

最好使用一些指定的解析器,例如BeautifulSoup来自python

#!/usr/bin/env python3
from bs4 import BeautifulSoup

with open('file.html') as f:
    content = f.read()
    soup = BeautifulSoup(content, "html.parser")

p_contents=[]
for p in soup.find_all('p'):
    p_content = p.get_text().strip()
    
    if p_content in p_contents:
        p.extract()
    else:
        p_contents.append(p_content)

print(soup)

使用awk

awk -v start="<p>" -v end="</p>" '
    $0 == start { tag=$0; in_tag=1 }
    !in_tag
    in_tag && ( $0 != start && $0 != end ) { tag=tag"\n"$0 }
    $0 == end { if (!seen[tag]++) { print tag"\n"$0 }; in_tag=0 }
' file.html

答案3

事实是:我不知道如何在awk.和sed你一起可以做到

sed 'N;/\n</{P;D;};G;/\(\n[^<]*\n\).*\1/{N;d;};s/\n\n.*//;s/\n$//;H' file

这个想法是使用一个N;P;D循环来始终一起处理两条线。如果第二个不是标语,请测试保留空间中保留的行是否重复。d删除重复项并将新的原件附加到H旧空间以供将来参考。

请先在没有选项的情况下进行测试-i,以免弄乱您的文件。如果它有效并且sed解决方案适合您,我将添加更详细的解释。

相关内容