
以下に示すように、複数の同一で重複した項目を含むファイルがあります。
123 abc nhjk
123 abc cftr
123 abc xdrt
123 def nhjk
123 def cftr
123 def xdrt
if(列)の組み合わせフィールド1そしてフィールド2一致する場合は、最初の一致時間を維持するだけです。だからそれ以来123そしてアルファベット最初の行の一致123そしてアルファベット2行目の場合は、1行目のみを保持します。より詳細に比較すると、最初の行と3番目の行も一致するため、最初の行だけが保持されます。
ただし、1行目と4行目の場合123そして123一致するがアルファベットそして定義一致するものがないため、両方の行が保持されます。
したがって、最終出力は次のようになります。
123 abc nhjk
123 def nhjk
答え1
1つの方法は、元のファイルの順序は維持されないかもしれませんが、-u
フラグを使用することです。sort
sort -k1,1 -k2,2 -u file
ファイルの順序を維持しながら重複排除を完了する必要がある場合
awk '!a[$1, $2]++' file
答え2
RobertLと1_CRの素晴らしい答え
より柔軟なシェルスクリプトアプローチを好む場合は、次のスクリプトを試してください。
#!/bin/sh
rm output.txt
touch output.txt
while read line
do
field1=$( echo $line | cut -d" " -f1)
field2=$( echo $line | cut -d" " -f2)
lookup="$field1 $field2"
if [ -z $(grep "$lookup" output.txt) ]
then
echo $line >> output.txt
fi
done < input.txt
cat output.txt
exit 0
明らかに大幅に短縮できますが、各ステップを非常に明確にしたかったのです。
楽しんでください。
編集する:
@RobertLが投稿したリンクに沿っていくつかのオプションをテストした後、このスクリプトが大幅に改善されたことに同意する必要があります。私は使用します
#!/bin/sh
sort -k1,2 -u "$@" |
while read line
do
echo "$line"
done
これに関する唯一の質問はRobertLですが、なぜ以下を使用しますか?
sort -k1,2 -k2,2 -u
変える
sort -k1,2 -u
私のテストによると、ソートが機能します。
$ cat robertL.sh
#!/bin/sh
sort -k1,1 -k2,2 -u "$@" |
while read line
do
echo "$line"
done
$ time ./robertL.sh < input.txt
123 abc nhjk
123 def nhjk
real 0m0.022s
user 0m0.014s
sys 0m0.009s
しかし、もう一つは2倍速いです。
$ cat process_v2.sh
#!/bin/sh
sort -k1,2 -u "$@" |
while read line
do
echo "$line"
done
$ time ./process_v2.sh < input.txt
123 abc nhjk
123 def nhjk
real 0m0.012s
user 0m0.006s
sys 0m0.009s
したがって、結論としてRobertLのアプローチを強くお勧めしますが、ここにあるすべての内容を常に例として、問題に対する絶対的な真実や最終的な解決策ではありません。最善の方法は答えを介して指示を見つけることだと思います。
答え3
出力の各レコードを集中的に処理する必要がある場合は、出力の各行を読み取るフィルタを作成できます。 ソート/固有アルゴリズム内でレコードを処理しないでください。
元のスクリプトは処理されるレコード100個あたり約1秒かかります。ソートされた出力を読み取るスクリプトは、380,000を超えるレコードを処理するのに3/10秒もかかりません。元のスクリプトが必要です。約1時間あまりにも多くのデータを処理するには。
1時間は10分の3秒に例えられます!
さらに、元のスクリプトはほとんどの時間をシステム時間(プロセスブランチ、IO実行など)で費やします。これはパフォーマンスの問題のもう1つの悪い兆候です。
元のスクリプトを実行します。
$ wc -l input.txt
1536 input.txt
$ time ./jesus.sh
rm: cannot remove ‘output.txt’: No such file or directory
123 abc nhjk
123 def nhjk
real 0m16.997s #<<<---------
user 0m3.546s
sys 0m16.329s #<<<---------
この新しいサンプルスクリプトを実行するときにオペレーティングシステムコードにかかる実行時間はごく一部です。
$ time ./RobertL.sh < input.txt
123 abc nhjk
123 def nhjk
real 0m0.011s #<<<---------
user 0m0.004s
sys 0m0.007s #<<<---------
これで、大規模なデータセットで新しいスクリプトを実行し、元のスクリプトを完了するのに少なくとも1時間かかります。
$ wc -l data388440.txt
388440 data388440.txt
$ time ./RobertL.sh < data388440.txt
123 abc nhjk
123 def nhjk
real 0m0.282s #<<<---------
user 0m0.728s
sys 0m0.032s #<<<---------
新しいサンプルスクリプト:
$ cat RobertL.sh
#!/bin/sh
sort -k1,1 -k2,2 -u "$@" |
while read line
do
echo "$line"
done
kshをインストールせずに実行するように変更されたソーススクリプト:
$ cat jesus.sh
#!/bin/bash
#!/bin/sh # does not accept [[ ... ]]
#!/bin/ksh # not installed on ubuntu by default
rm output.txt
touch output.txt
while read line
do
field1=$( echo $line | cut -d" " -f1)
field2=$( echo $line | cut -d" " -f2)
lookup="$field1 $field2"
if [[ -z $(grep "$lookup" output.txt) ]]
then
echo $line >> output.txt
fi
done < input.txt
cat output.txt
exit 0
入力データは元の6行のサンプルデータを繰り返し生成し、データにはほぼすべての重複履歴が含まれています。
答え4
削除する行がすべて連続していて、キーの長さが等しい場合は、次を使用できます。
$ uniq --check-chars=8 <<EOF
123 abc nhjk
123 abc cftr
123 abc xdrt
123 def nhjk
123 def cftr
123 def xdrt
EOF
123 abc nhjk
123 def nhjk
$