0

DUPレコードを含むファイルがあります(DUPは列にあります)。ファイル内の最後の複製レコードのみを保持し、他のすべての複製を別のファイルに移動したいと考えています。

ファイル:入力

foo j
bar bn
bar b
bar bn
bar bn
bar bn
kkk hh
fjk ff
foo jj
xxx tt
kkk hh

次の awk ステートメントを使用して、最後のオカレンスを保持しています -

awk '{line=$0; x[$1]=line;} END{ for (key in x) print x[key];}' input > output

ファイル:出力

foo jj
xxx tt
fjk ff
kkk hh
bar bn

繰り返しレコードを別のファイルに移動するにはどうすればよいですか (最後のレコードを残します)。

1つのファイルに移動foo jすると、d_outputと言っfoo jjて出力ファイルに保持します

4

3 に答える 3

2

トリックはtac、最初にファイルを逆にするために使用されます(最後よりも最初の一致を取得する方が簡単です)

$ tac file | awk 'a[$1]++{print $0 > "dup";next}{print $0 > "output"}'

$ cat output
kkk hh
xxx tt
foo jj
fjk ff
bar bn

$ cat dup
kkk hh
bar bn
bar bn
bar b
bar bn
foo j

編集:

100万ラインを超える現在の3つのソリューションのベンチマーク値は次のとおりです。

sudo_o

real    0m2.156s
user    0m1.004s
sys     0m0.117s

kent

real    0m2.806s
user    0m2.718s
sys     0m0.080s

scrutinizer

real    0m4.033s
user    0m3.939s
sys     0m0.082s

ここで確認してくださいhttp://ideone.com/IBrNeh

ファイルを使用している私のローカルマシンでseq 1 1000000 > bench

# sudo_o
$ time tac bench | awk 'a[$1]++{print $0 > "dup";next}{print $0 > "output"}' 

real    0m0.729s
user    0m0.668s
sys     0m0.101s

# scrutinizer
$ time awk 'NR==FNR{A[$1]=NR; next} A[$1]!=FNR{print>f; next}1' f=dups bench bench > output

real    0m1.093s
user    0m1.016s
sys     0m0.070s

# kent 
$ time awk '$1 in a{print a[$1]>"dup.txt"}{a[$1]=$0}END{for(x in a)print a[x]}' bench > output

real    0m1.141s
user    0m1.055s
sys     0m0.080s
于 2013-03-15T21:03:09.493 に答える
2

ツールが好きtacrevいいです!ただし、それらはすべてのディストリビューションのデフォルトではありません。特に、質問にタグを付けていることがわかりましたunix。またtac、output/dup.txt の順序を変更します。順序を維持する必要がある場合は、順序を維持するための特別な努力が必要です。

この行を試してください:

awk '$1 in a{print a[$1]>"dup.txt"}{a[$1]=$0}END{for(x in a)print a[x]}' file

あなたの例で:

kent$  awk '$1 in a{print a[$1]>"dup.txt"}{a[$1]=$0}END{for(x in a)print a[x]}' file
foo jj
xxx tt
fjk ff
kkk hh
bar bn

kent$  cat dup.txt 
bar bn
bar b
bar bn
bar bn
foo j
kkk hh
于 2013-03-15T21:43:09.743 に答える
2

入力ファイルを 2 回読み取って順序を維持する別のオプションを試すことができます。

awk 'NR==FNR{A[$1]=NR; next} A[$1]!=FNR{print>f; next}1' f=dups file file

出力:

bar bn
fjk ff
foo jj
xxx tt
kkk hh

重複:

$ cat dups
foo j
bar bn
bar b
bar bn
bar bn
kkk hh

@Sudo_O @WilliamPursell @user2018441。Sudo_O 性能テストお疲れ様でした。私は自分のシステムでそれらを再現しようとしましたが、tac利用できないため、Kent のバージョンと私のバージョンでテストしましたが、私のシステムではそれらの違いを再現できませんでした。

cat更新: の代わりに を使用して、Sudo_O のバージョンでテストしましtacた。システムでは/dev/null に出力する場合と出力する場合tacに 0.2 秒の差がありました(この投稿の下部を参照)。taccat

私が得た:

Sudo_O
$ time cat <(seq 1 1000000) | awk 'a[$1]++{print $0 > "/dev/null";next}{print $0 > "/dev/null"}'

real    0m1.491s
user    0m1.307s
sys     0m0.415s

kent
$ time awk '$1 in a{print a[$1]>"/dev/null"}{a[$1]=$0}END{for(x in a)print a[x]}' <(seq 1 1000000) > /dev/null

real    0m1.238s
user    0m1.421s
sys     0m0.038s

scrutinizer
$ time awk 'NR==FNR{A[$1]=NR; next} A[$1]!=FNR{print>f; next}1' f=/dev/null <(seq 1 1000000) <(seq 1 1000000) > /dev/null

real    0m1.422s
user    0m1.778s
sys     0m0.078s

--

私が得た代わりにファイルを使用する場合seq

Sudo_O
$ time cat <infile | awk 'a[$1]++{print $0 > "/dev/null";next}{print $0 > "/dev/null"}'

real    0m1.519s
user    0m1.148s
sys     0m0.372s


kent
$ time awk '$1 in a{print a[$1]>"/dev/null"}{a[$1]=$0}END{for(x in a)print a[x]}' <infile > /dev/null

real    0m1.267s
user    0m1.227s
sys     0m0.037s

scrutinizer
$ time awk 'NR==FNR{A[$1]=NR; next} A[$1]!=FNR{print>f; next}1' f=/dev/null <infile <infile > /dev/null

real    0m0.737s
user    0m0.707s
sys     0m0.025s

おそらく、大きなファイルにも存在するキャッシュ効果が原因です..infileの作成には次の時間がかかりました。

$ time seq 1 1000000 > infile

real    0m0.224s
user    0m0.213s
sys     0m0.010s

別のシステムでテスト済み:

$ time cat <(seq 1 1000000) > /dev/null

real    0m0.764s
user    0m0.719s
sys     0m0.031s
$ time tac <(seq 1 1000000) > /dev/null

real    0m1.011s
user    0m0.820s
sys     0m0.082s
于 2013-03-15T23:26:59.200 に答える