添加增长领域的领域Unix

时间:2015-12-04 03:34:05

标签: regex unix awk sed grep

我有一个看起来像

的成绩簿文件

StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02: 0123:Smith:Jon:100:80:80:100:90: 0987:Williams:Pat:20:30:35:46:50: 0654:Bar:Foo:100:100:100:100:100:

我需要为每个学生添加所有hws / quizes /考试/项目,并将总数追加到相应行的末尾

示例输出文件可以是

StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02:hT:qT:eT:pT 0123:Smith:Jon:100:80:80:100:90:100:170:80:100: 0987:Williams:Pat:20:30:35:46:50:20:80:35:46: 0654:Bar:Foo:100:100:100:100:100:100:200:100:100:

输出文件不必是同一个文件,但请记住,标题行(第1行)中成绩的顺序可以是任何内容。因此,作业的顺序可以是任何顺序。

我假设我必须使用grep在文件中搜索包含" hw" /"测验" /"考试" /&#的所有字段34;凸出"并获得相应的字段。然后浏览每一行并单独添加hw / quiz / exam / proj的总计。

使用awk可能会更容易吗?

3 个答案:

答案 0 :(得分:1)

$ cat tst.awk
BEGIN { FS=OFS=":" }
NR==1 {
    for (i=4;i<NF;i++) {
        name = substr($i,1,1) "T"
        nr2name[i] = name
        if (!seen[name]++) {
            names[++numNames] = name
        }
    }

    printf "%s", $0
    for (nameNr=1; nameNr<=numNames; nameNr++) {
        printf "%s%s", names[nameNr], OFS
    }
    print ""
    next
}
{
    delete tot
    for (i=4;i<NF;i++) {
        name = nr2name[i]
        tot[name] += $i
    }

    printf "%s", $0
    for (nameNr=1; nameNr<=numNames; nameNr++) {
        printf "%s%s", tot[names[nameNr]], OFS
    }
    print ""
}

$ awk -f tst.awk file
StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02:hT:qT:eT:pT:
0123:Smith:Jon:100:80:80:100:90:100:170:80:100:
0987:Williams:Pat:20:30:35:46:50:20:80:35:46:
0654:Bar:Foo:100:100:100:100:100:100:200:100:100:

答案 1 :(得分:0)

这似乎可以胜任这项工作;但它错综复杂:

script.awk

BEGIN   { FS = ":"; OFS = FS }
NR == 1 {
            for (i = 4; i < NF; i++)
            {
                c = substr($i, 1, 1)
                if (!(c in columns)) order[n++] = c
                columns[c]++
                letter[i] = c
            }
            nf = NF
            for (i = 0; i < n; i++)
                $(i+nf) = order[i] "T"
            print $0 OFS
            next
        }
        {
            for (c in columns) total[c] = 0
            for (i = 4; i < NF; i++)
            {
                c = letter[i]
                total[c] += $i
            }
            nf = NF
            for (i = 0; i < n; i++)
            {
                c = order[i]
                $(i+nf) = total[c]
            }
            print $0 OFS
        }

说明:

BEGIN

  • 设置输入和输出字段分隔符。

NR == 1

  • 在学生ID和姓名字段后面的字段上循环。
  • 提取第一个字母。
  • 如果以前没有看过这封信,请在order中注明,并增加总数(n)。
  • 增加看到该字母的次数。
  • 记录当前列的字母。
  • 按顺序在现有列之后添加新列。
  • 打印该行以及一个尾随输出字段分隔符(也称为OFS或:)。
  • 请注意,$ NF为空,因为数据中的结尾为:,因此(awk脚本异常),i < NF而不是i <= NF

每一行:

  • 重置每个字母的总计。
  • 对于每个评分字段,找到该列所属的字母(letter[i])。
  • 将该列添加到该字母的总计中。
  • 对于按顺序排列的每个额外字段,请将相应额外字段的值设置为该字母的总计。
  • 打印记录加上额外的冒号(又名OFS)。

data

StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02:
0123:Smith:Jon:100:80:80:100:90:
0987:Williams:Pat:20:30:35:46:50:
0654:Bar:Foo:100:100:100:100:100:

示例输出

$ awk -f script.awk data

StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02:hT:qT:eT:pT:
0123:Smith:Jon:100:80:80:100:90:100:170:80:100:
0987:Williams:Pat:20:30:35:46:50:20:80:35:46:
0654:Bar:Foo:100:100:100:100:100:100:200:100:100:
$

问题中此示例和示例输出之间的唯一区别是标题行上的尾部冒号,以便与数据行(和输入)保持一致。

答案 2 :(得分:0)

很少适应   - 总计顺序不一样(动态)   - 总计名称使用完整的激进名称,不包括最后2位数字   - 使用参数定义第一个字段,其中包含要计数的数据(此处为第4个-v 'St=4'

awk -v 'St=4' '
   BEGIN{FS=OFS=":"}
   NR==1 {
      printf "%s",$0
      for(i=St;i<=(nf=NF-1);i++){
         tn=$i;sub(/..$/,"T",tn)
         T[tn]=0;TN[i]=tn
         }
      Sep=""
      for(t in T){
          printf "%s%s",Sep,t;Sep=OFS
          }
      print Sep
      next
      }
   {
      for(i=St;i<=nf;i++){
         T[TN[i]]+=$i
         }
      for(i=1;i<=nf;i++)printf "%s%s",$i,OFS
      Sep=""
      for(t in T){
         printf "%s%s",Sep,T[t]
         T[t]=0;Sep=OFS
         }
      print Sep
   }' YourFile

StudentID:LastName:FirstName:hw01:quiz01:exam01:proj01:quiz02:examT:quizT:hwT:projT:
0123:Smith:Jon:100:80:80:100:90:80:170:100:100:
0987:Williams:Pat:20:30:35:46:50:35:80:20:46:
0654:Bar:Foo:100:100:100:100:100:100:200:100:100: