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
我从数据库中获取此数据,其中第一列中有月份,第三列中有第二列每个学生的标记。现在我想以这样的方式进行编辑,使其在第一列中包含名称,在第二列中包含 2016-10 的标记,然后在第三列中包含 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
输出为每个学生一行,成绩按月份降序排列。
对于那些喜欢将代码分布在多行中的人:
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
如果这是一次性的事情,并且您的数据按照示例(已订购,仅两个月等),那么这也可以:
awk 'NR==1{next}NR%2{print $3;next}{printf "%s\t%s\t",$2,$3}' data