特定の条件が満たされたときに 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

awkxml構文解析/データに適したツールではなく、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

真実は:私はあなたと何ができるかわかりませんawksed

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

アイデアは、N;P;Dループを使用して常に2行を一緒に処理することです。 2番目がバナーでない場合は、予約済みスペースに予約済み行が重複しているかどうかをテストします。d重複したアイテムを削除してH後で参照できるように、新しいソースを既存のスペースに添付します。

-iファイルが複雑にならないように、まずオプションなしでテストしてみてください。効果があり、sedソリューションが効果がある場合は、より詳細な説明を追加します。

関連情報