ファイル内の重複行を削除せずに識別しますか?


11

エントリの長いリストを持つテキストファイルとしての参照があり、それぞれに2つ(またはそれ以上)のフィールドがあります。

最初の列は参照のURLです。2列目はタイトルで、エントリの作成方法によって多少異なる場合があります。存在する場合と存在しない場合がある3番目のフィールドについても同じです。

最初のフィールド(参照URL)が同一のエントリを特定しますが、削除しません。私は知ってsort -k1,1 -uいますが、それは最初のヒットを除くすべてを自動的に(非対話的に)削除します。どちらを保持するかを選択できるように、私に通知する方法はありますか?

同じ最初のフィールド(http://unix.stackexchange.com/questions/49569/)を持つ3行の以下の抜粋では、追加のタグ(ソート、CLI)があり、行#1と#3を削除するため、行2を保持します。

http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

そのような「重複」を特定するのに役立つプログラムはありますか?次に、行#1と#3を個人的に削除して手動でクリーンアップできますか?


私はあなたの例をよく理解していません...入力と期待される出力のより単純化されたバージョンを提供できますか?
オリ

今よりはっきりしているかどうか見てください?
DKボーズ14年

回答:


9

あなたの質問を理解したら、次のようなものが必要だと思います。

for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done

または:

for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done

file.txt興味のあるデータを含むファイルはどこにありますか。

出力には、最初のフィールドが2回以上見つかった行と行の数が表示されます。


3
ありがとう: cut -d " " -f1 file.txt | uniq -d素敵な出力をくれます。
DKボーズ14年

@DKBoseおそらくもっと多くの可能性がありますが、私はあなたのコマンドも使用したいと思いました。
ラドゥラデアヌ14年

ありがとう。2番目のコマンドは、私が好きなコマンドです。最初のものを削除できます。そして、あなたもいいコードを説明すると:)
DKボーズ14年

10

これは、uniqコマンドで解決できる古典的な問題です。uniq重複する連続した行を検出し、重複を削除(-u--unique)または重複のみを保持(-d--repeated)できます。

重複する行の順序は重要ではないため、最初に並べ替える必要があります。次に、uniq一意の行のみを印刷するために使用します。

sort yourfile.txt | uniq -u

オプションの重複数を出力する-c--count)オプションもあり-dます。詳細については、のマニュアルページuniqを参照してください。


最初のフィールドの後の部分が本当に気にならない場合は、次のコマンドを使用して重複キーを見つけ、そのキーの各行番号を印刷できます(別の行| sort -nを追加して、出力を行でソートします)。

 cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D

(最初のフィールドをキーとして使用して)重複する行を表示するため、直接使用することはできませんuniq。自動化を困難にする問題は、タイトル部分が異なることですが、プログラムはどのタイトルを最終タイトルと見なすべきかを自動的に決定することはできません。

これscript.awkは、テキストファイルを入力として取得し、重複する行をすべて印刷するAWKスクリプト(に保存)で、削除する行を決定できます。(awk -f script.awk yourfile.txt

#!/usr/bin/awk -f
{
    # Store the line ($0) grouped per URL ($1) with line number (NR) as key
    lines[$1][NR] = $0;
}
END {
    for (url in lines) {
        # find lines that have the URL occur multiple times
        if (length(lines[url]) > 1) {
            for (lineno in lines[url]) {
                # Print duplicate line for decision purposes
                print lines[url][lineno];
                # Alternative: print line number and line
                #print lineno, lines[url][lineno];
            }
        }
    }
}

これは私が望むものに近いと思いますが、 `-f、--skip-fields = Nの反対が必要です(最初のN個のフィールドの比較は避けてください)。つまり、最初のフィールドであるURLのみを考慮したいのです。
DKボーズ14年

@DKBose 固定の文字数に制限する-w--check-chars)オプションがありますが、例を見ると、可変の最初のフィールドがあります。以来uniq、フィールドの選択をサポートしていない、あなたは回避策を使用する必要があります。簡単なので、AWKの例を含めます。
Lekensteyn

はい、私はただ見ていた-wが、最初のフィールドの長さは可変:(ある
DKボーズ

@DKBose最新の編集を参照してください
Lekensteyn

1
私はawkを取得しています:script.awk:line 4:構文エラー[awk:script.awk:line 10:構文エラーat or near [awk:script.awk:line 18:構文エラーat or near}
DKボーズ14年

2

これを正しく読めば、必要なのは

awk '{print $1}' file | sort | uniq -c | 
    while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done

これは、デュープを含む行の番号と行自体を出力します。たとえば、次のファイルを使用します。

foo bar baz
http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
bar foo baz
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
baz foo bar
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

次の出力が生成されます。

2:http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
4:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
6:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

行番号のみを印刷するには、次のようにします。

awk '{print $1}' file | sort | uniq -c | 
 while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1

そして、行のみを印刷するには:

awk '{print $1}' file | sort | uniq -c | 
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-

説明:

awkこのスクリプトは、ちょうど第一スペースはファイルのフィールドを分離出力します。$NN番目のフィールドを印刷するために使用します。sortそれをソートし、uniq -c各行の出現回数をカウントします。

これは、その後に渡されたwhileとして出現回数を節約し、ループ$numのようにライン$dupeとあれば$num1以上である(それは一度少なくとも重複していますので)それは使用して、その行のファイルを検索します-n行番号を印刷します。--伝えgrep次にくるものがときに役立つコマンドラインオプション、ではないこと$dupeを始めることができます-


1

リストの中で最も冗長なものは間違いなく、おそらくもっと短くなるでしょう:

#!/usr/bin/python3
import collections
file = "file.txt"

def find_duplicates(file):
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    splitlines = [
        (index, data[index].split("  ")) for index in range(0, len(data))
        ]
    lineheaders = [item[1][0] for item in splitlines]
    dups = [x for x, y in collections.Counter(lineheaders).items() if y > 1]
    dupsdata = []
    for item in dups:
        occurrences = [
            splitlines_item[0] for splitlines_item in splitlines\
                       if splitlines_item[1][0] == item
            ]
        corresponding_lines = [
            "["+str(index)+"] "+data[index] for index in occurrences
            ]
        dupsdata.append((occurrences, corresponding_lines))

    # printing output   
    print("found duplicates:\n"+"-"*17)
    for index in range(0, len(dups)):
        print(dups[index], dupsdata[index][0])
        lines = [item for item in dupsdata[index][1]]
        for line in lines:
            print(line, end = "")


find_duplicates(file)

次のようなテキストファイルを与えます:

monkey  banana
dog  bone
monkey  banana peanut
cat  mice
dog  cowmeat

次のような出力:

found duplicates:
-----------------
dog [1, 4]
[1] dog  bone
[4] dog  cowmeat
monkey [0, 2]
[0] monkey  banana
[2] monkey  banana peanut

削除する行を選択したら:

removelist = [2,1]

def remove_duplicates(file, removelist):
    removelist = sorted(removelist, reverse=True)
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    for index in removelist:
        data.pop(index)
    with open(file, "wt") as sourcefile:
        for line in data:
            sourcefile.write(line)

remove_duplicates(file, removelist)

0

次のソートを参照してくださいfile.txt

addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/ ::: C2P per-element
addons.mozilla.org/en-us/firefox/addon/prospector-oneLiner/ ::: OneLiner
askubuntu.com/q/21033 ::: What is the difference between gksudo and gksu?
askubuntu.com/q/21148 ::: openoffice calc sheet tabs (also askubuntu.com/q/138623)
askubuntu.com/q/50540 ::: What is Ubuntu's Definition of a "Registered Application"?
askubuntu.com/q/53762 ::: How to use lm-sensors?
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
stackoverflow.com/q/4594319 ::: bash - shell replace cr\lf by comma
stackoverflow.com/q/4594319 ::: shell replace cr\lf by comma
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence - Ubuntu Wiki
www.youtube.com/watch?v=1olY5Qzmbk8 ::: Create new mime types in Ubuntu
www.youtube.com/watch?v=2hu9JrdSXB8 ::: Change mouse cursor
www.youtube.com/watch?v=Yxfa2fXJ1Wc ::: Mouse cursor size

リストが短いため、(ソート後)重複が3セットあることがわかります。

次に、たとえば、以下を保持することを選択できます。

askubuntu.com/q/53762 ::: How to use lm-sensors?

のではなく

askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors

しかし、長いリストの場合、これは困難です。1つが示唆する2つの答えuniqと、もう1つが示唆する2つの答えに基づいて、cutこのコマンドで希望する出力が得られることがわかりました。

$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$

私の回答をの別のバリアントで更新しましたcut。重複排除作業を行っている場合は、行番号が非常に役立つ場合があります。すべての重複を印刷するには、の-D代わりにオプションを使用します-d
Lekensteyn

for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n $dup file.txt; done私の答えのように、あなたがよりよく使うと思います。興味のある内容についてより良いプレビューを提供します。
ラドゥラデアヌ

0

彼女は私がそれを解決した方法です:

file_with_duplicates:

1,a,c
2,a,d
3,a,e <--duplicate
4,a,t
5,b,k <--duplicate
6,b,l
7,b,s
8,b,j
1,b,l
3,a,d <--duplicate
5,b,l <--duplicate

列1および2でソートおよび重複除外されたファイル

sort -t',' -k1,1 -k2,2 -u file_with_duplicates

列1および2のみでソートされたファイル

sort -t',' -k1,1 -k2,2 file_with_duplicates

違いのみを表示:

diff <(sort -t',' -k1,1 -k2,2 -u file_with_duplicates) <(sort -t',' -k1,1 -k2,2 file_with_duplicates)

 3a4
   3,a,d
 6a8
   5,b,l
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.