使用AWK重新组织命名字段

时间:2010-06-29 06:46:32

标签: awk

我必须处理具有许多字段的各种输入文件,这些字段是任意排列的,但是所有字段都一致地命名并标有标题行。需要重新格式化这些文件,使得所有期望的字段按特定顺序排列,不相关的字段被剥离并且缺少字段。我希望使用AWK来处理这个问题,因为在过去处理与字段相关的困境时,它对我做得很好。

经过一段时间的磨砺后,我最终得到了类似下面的内容(从内存中写入,未经测试):

# imagine a perfectly-functional BEGIN {} block here

NR==1 {
  fldname[1] = "first_name"
  fldname[2] = "last_name"
  fldname[3] = "middle_name"
  maxflds = 3

  # this is just a sample -- my real script went through forty-odd fields

  for (i=1;i<=NF;i++) for (j=1;j<=maxflds;j++) if ($i == fldname[j]) fldpos[j]=i
}

NR!=1 {
  for (j=1;j<=maxflds;j++) {
    if (fldpos[j]) printf "%s",$fldpos[j]
    printf "%s","/t"
  }
  print ""
}

现在这个解决方案正常工作。我运行它,我的输出正是我想要的。没有抱怨。但是,对于任何超过三个字段的东西(例如我必须使用的四十多个字段),这是一个非常痛苦的冗余代码,总是有并且总是会打扰我。并且不得不在其他地方插入一块混乱的想法让我不寒而栗。

每次看到它我都会死一点。

我确信那里必须有更优雅的解决方案。或者,如果没有,也许有一种工具更适合这种任务。 AWK在它自己的域名中很棒,但是我担心我可能会因为这个而扩展它的限制。

有什么见解?

1 个答案:

答案 0 :(得分:0)

我能想到的唯一建议是将初始数组设置移动到BEGIN块中,并从循环中的单独模板文件中读取有序字段名称。然后你的awk程序只包含没有嵌入数据的循环。您的外部模板文件将是一个简单的换行符分隔列表。

BEGIN {while ((getline < "fieldfile") > 0) fldname[++maxflds] = $0}

当然,您仍然会以与现在相同的方式阅读标题行。但是,我发现您可以使用关联数组并将嵌套的for循环减少为单个for循环。像(未经测试)的东西:

BEGIN {while ((getline < "fieldfile") > 0) fldname[$0] = ++maxflds}

NR==1 {
    for (i=1;i<=NF;i++) fldpos[i] = fldname[$i]
}