我必须处理具有许多字段的各种输入文件,这些字段是任意排列的,但是所有字段都一致地命名并标有标题行。需要重新格式化这些文件,使得所有期望的字段按特定顺序排列,不相关的字段被剥离并且缺少字段。我希望使用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
在它自己的域名中很棒,但是我担心我可能会因为这个而扩展它的限制。
有什么见解?
答案 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]
}