これは驚くほど難しいソート基準です。このコードは機能しますが、かなり醜いです:
data=${1:-data}
awk '{ print $1 }' $data |
sort |
uniq -c |
sort -k2 |
join -1 2 -2 2 -o 1.1,2.1,2.2,2.3 - <(awk '{ print NR, $0 }' $data | sort -k2) |
sort -k1,1nr -k3,3 -k2n |
awk 'BEGIN{OFS="\t"} { print $3, $4 }'
「プロセス置換」には4.xを想定bash
していますが、組み込みawk
のソートは使用していません(これは POSIX と比較したGNU拡張awk
です)。明示的な一時ファイルを使用すると、プロセス置換なしでシェルで動作させることができます。
data=${1:-data} # File named on command line, or uses name 'data'
awk '{ print $1 }' $data | # List of names
sort | # Sorted list of names
uniq -c | # Count occurrences of each name
sort -k2 | # Sort in name order
join -1 2 -2 2 -o 1.1,2.1,2.2,2.3 - <(awk '{ print NR, $0 }' $data | sort -k2) |
# The process substitution numbers each record in sequence and sorts in name order
# The join matches the names (column 2) and outputs the frequency, record number, name, value
sort -k1,1nr -k3,3 -k2n | # Sort on frequency reversed, name, original line number
awk 'BEGIN{OFS="\t"} { print $3, $4 }' # Print name and value
GNUawk
と組み込みの並べ替え、または Perl または Python を使用することは、おそらくこれよりも優れています。
元のデータの場合、出力は次のようになります。
Peter 5
Peter 7
Peter 8
Joe 8
Joe 4
Laura 3
この拡張バージョンのデータを考えると、次のようになります。
Peter 5
Joe 8
Peter 7
Peter 8
Joe 4
Laura 3
Peter 50
Joe 80
Peter 70
Peter 80
Joe 40
Laura 30
Peter 700
Peter 800
Peter 7002
Peter 8002
Peter 7000
Peter 8000
Peter 7001
Peter 8001
Pater 50
Jae 80
Pater 70
Pater 80
Jae 40
Laura 30
出力は次のとおりです。
Peter 5
Peter 7
Peter 8
Peter 50
Peter 70
Peter 80
Peter 700
Peter 800
Peter 7002
Peter 8002
Peter 7000
Peter 8000
Peter 7001
Peter 8001
Joe 8
Joe 4
Joe 80
Joe 40
Laura 3
Laura 30
Laura 30
Pater 50
Pater 70
Pater 80
Jae 80
Jae 40
この-k3,3
データセットにはソート条件が必要です。これは、Laura のエントリを Pater のエントリの前にソートします (省略した場合、これら 2 つのリストがインターリーブされます)。