2010-06-29 112 views
1

我必须处理各种输入文件,其中包含许多字段,任意排列,但所有字段都一致地命名并标记为标题行。这些文件需要重新格式化,以便所有需要的字段都按特定的顺序排列,剥离不相关的字段并填充缺失的字段。我曾经希望用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在它自己的领域是很棒的,但我担心我可能会拉伸它是限制一些与此。

任何见解?

回答

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] 
} 
+0

我喜欢的关联数组的想法,但据我所知有保证这个数组的顺序没有干净的方式同时印刷,短从头开始,因此写了排序功能(不GAWK的无不幸的是)。我想''fldpos [fldname [$ i]] = i'在标题循环中可以工作,因为它给了我一个整数键以在打印时循环... – goldPseudo 2010-06-29 15:19:46

+0

@goldPseudo:哎呀,我没在想关于那个。我认为你的想法可行。 – 2010-06-29 17:23:27