Month Name Marks
2016-10 Sam 58
2016-09 Sam 77
2016-10 John 64
2016-09 John 47
2016-10 Mark 71
2016-09 Mark 38
2016-10 Steve 83
2016-09 Steve 39
私は最初の列に月があり、2番目の列に各学生のスコアがあるデータベースからこのデータを取得しています。さて、最初の列に名前があり、2番目の列に2016-10タグがあり、3番目の列に2016-09タグがあるように編集したいと思います。
答え1
入力データが「grades」というファイルにあるとし、次のことを試してください。
$ awk 'BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"} NR==1{next} {m[$1]; n[$2]; g[$2,$1]=$3} END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}' grades | column -t
Steve 83 39
Sam 58 77
Mark 71 38
John 64 47
出力は学生ごとに 1 行で、成績は月ごとに降順でソートされます。
コードを複数行にわたって分散したい場合:
gawk '
BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}
NR==1{
next
}
{
m[$1]
n[$2]
g[$2,$1]=$3
}
END{
for (name in n) {
printf "%s",name
for (month in m)
printf " %s", g[name,month]
print""
}
}
' grades | column -t
どのように動作しますか?
BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}
これは、配列がインデックスごとにソートされることを望んでいることをawkに伝えます。これがGNUの特徴です。
NR==1{next}
これはawkに最初の行をスキップするように指示します。出力ファイルにヘッダーを追加するには、ここで行うことができます。
m[$1]
これは、awkに連想配列に現在の月のエントリを追加するように指示します
m
。入力にどの月があるかを追跡するためにのみ使用されるため、値を割り当てる必要はありません。n[$2]
これは、連想配列に生徒名のエントリを追加するようにawkに指示します
n
。入力にどの月があるかを追跡するためにのみ使用されるため、値を割り当てる必要はありません。g[$2,$1]=$3
これにより、連想配列の生徒名、月キーの下の値として成績が割り当てられます
g
。END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}
ファイルの終わりに達すると、各生徒のすべての名前と成績を印刷します。
column -t
このオプションのステップは出力をきれいにします。
答え2
隔月で必要な場合
sed '
2~2{ #for even lines
N #attach next line
s/\(\S\+ \)\(\S\+ \)[0-9]*\n\(\S\+\).*/\2\1\3/ #rearrange two line
}
1c\Name Month1 Month2 #output new header
' file.data
または二重マット
sed '
1!N #from second line attach next line
s/\S\+ // #remove first field (2016-10)
s/\n.* / / #remove 2 fields in attached line
t #ommit 1st line
s/$/1 Marks2/ #arrange header
' file.data
その他のバージョン
echo 'Name Marks1 Marks2' ;\
paste -sd' \n' <(tail -n +2 file.data) |
cut -d' ' -f 2,3,6
答え3
やや粗雑な例:
ここでは、変数をm
含める日付とその順序をカンマ区切り文字列に設定します。以下の例に基づいて、次のようになります。
m=2016-10,2016-09
これは以下を提供します。
Name 2016-10 2016-09
これを行うには、名前が一意でなければならず、空白があってはなりません。
awk -v m=2016-10,2016-09 '
NR==1{next}
{
# Set array x[name][month]=marks
x[$2][$1]=$3
}
END {
split(m, k, ",")
printf "Name"
for (v in k)
printf "\t%s", k[v]
for (e in x) {
printf "\n%s", e
for (v in k)
printf "\t%s", x[e][k[v]]
}
print ""
}
' data
出力例:
Name 2016-10 2016-09
Steve 83 39
Mark 71 38
John 64 47
Sam 58 77
合格column -t
:
Name 2016-10 2016-09
Steve 83 39
Mark 71 38
John 64 47
Sam 58 77
これはワンタイムで、データがはい(注文、2ヶ月のみの注文など)に従う場合にも機能します。
awk 'NR==1{next}NR%2{print $3;next}{printf "%s\t%s\t",$2,$3}' data