awkを使用して重複エントリのみを作成する

awkを使用して重複エントリのみを作成する

awk を使用して重複するアイテムを削除するのは非常に一般的で簡単です。ただし、1つの列のみを比較する場合は、重複した行のみを印刷する必要があります。私は次のコマンドを試しました。

awk 'seen[$2]++'

しかし、ご覧のように欠陥があります。重複した内容は印刷されますが、2回目以降にのみ印刷されます。私はちょうどunixとbashに慣れ始めましたが、解決策を私に説明していただきありがとうございます。

答え1

これを行う2つの方法があります。

  1. ファイルを2回繰り返します。

    最初の繰り返しでは、各$ 2の発生回数を数えます。
    2回目の反復では、数が1より大きい行だけが印刷されます。

    awk 'NR == FNR {count[$2]++; next} count[$2] > 1' file file
    
  2. データの単一反復:

    $2が表示される回数を数える必要があります。そして$2ごとにどの行が発生したかを覚えておいてください。

    この答えは、GNU awkを使用して配列の配列を表します。出力順序は入力データと同じにすることはできません。また、ファイル全体をメモリに保存する必要があります。

    gawk '
        { lines[$2][++count[$2]] = $0 }
        END {
            for (x in lines)
                if (count[x] > 1)
                    for (i=1; i<=count[x]; i++)
                        print lines[x][i]
        }
    ' file
    

入力ファイルを使用してテストします。

$ cat file
a b
b b
c b
a c
a d
b d
a e

と予想出力

a b
b b
c b
a d
b d

答え2

同じサンプル入力を使用グレンジャックマン回答

$ awk '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' file
a b
b b
c b
a d
b d
  • !seen[$2]++$2以前に体験できなかった場合:
    • fl[$2]=$0最初の行を保存してください。入力がソートされておらず、ファイルのどこにも重複が発生する可能性があると仮定するため、$2 一時変数ではなくベースとして保存してください。
    • c[$2]=1同様に count 変数を 1 に初期化します。
  • $2 in seen$2以前にこれが発生した場合:
    • if(c[$2]--){print fl[$2]}前の行が最初に印刷され、その後の一致条件が失敗するようにカウンタが減少されます。
    • print次に、現在の行を印刷します。


別の入力で

$ cat ip.txt 
6.2  : 897 : bar
3.1  : 32  : foo
1.2  : 123 : xyz
2.3  : 32  : baz
7.5  : 897 : boo

$ awk -F: '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' ip.txt 
3.1  : 32  : foo
2.3  : 32  : baz
6.2  : 897 : bar
7.5  : 897 : boo

順序は再発の発生方法によって異なります。

答え3

同じファイルを2回繰り返すと、行番号を便利なインデックスとして使用できます。これにより、ロジックがより明確になります。

awk 'NR == FNR {if ($2 in z) { y[z[$2]]; y[FNR] } z[$2]=FNR; next} (FNR in y)' file file

私はこの質問に答えるときに同様の技術を使用しました。


このトリックの基本は、Awkが単に参照で変数を生成し、配列要素が指定されindex in arraynameたインデックスで作成されたかどうかに応じて、設定がtrueまたはfalseを返すことです。

関連情報