如何读取具有固定长度定义的配置文件以相应地打印大文件

时间:2013-12-30 19:53:07

标签: unix awk

我有配置文件customer.cfg,它有2个字段:描述和列长度 如下:

ID ; 10
First Name ; 20
Last Name ; 20

我还有一个庞大的数据文件customer.dat,其中包含我想要阅读的数据,如下所示:

1234567890John                Armless
9         Eric                Clapton                      
10        Roger               Waters  

我想输入LINE NUMBER,CONFIG_FILE_NAME和DATA_FILE_NAME,awk应该能够根据.cfg文件的格式定义打印大文件中的数据:

例如:

示例1

Input: 2,customer.cfg,customer.dat

Outputs:

DataFileName: customer.dat
Line: 2
ID:9
First Name:Eric
Last Name:Clapton

示例2:

Input:all,customer.cfg,customer.dat

Outputs:

DataFileName: customer.dat
Line: 1
ID:1234567890
First Name:John
Last Name:Armless

DataFileName: customer.dat
Line: 2
ID:9
First Name:Eric
Last Name:Clapton

DataFileName: customer.dat
Line: 3
ID:10
First Name:Roger
Last Name:Waters

我对其他文件也有同样的看法,例如products.cfg& products.dat等,但始终遵循与上述相同的标准。所以我想要一些通用的东西也可以用于其他文件。

Considerations:
 - I want a solutions that uses AWK & printf
 - I can't install anything on this server.
 - My server is running AIX

3 个答案:

答案 0 :(得分:3)

您可以尝试以下脚本:(如果您使用的是Gnu Awk第4版,则可以使用FIELDWIDTHS而不是调用substr来简化脚本。

#! /bin/bash
lineno=all
cfgfile="customer.cfg"
datfile="customer.dat"

awk -v line="$lineno" -f p.awk FS=";" "$cfgfile" "$datfile"

其中p.awk是:

NR==FNR {
    a[++i]=$2
    next
}

line=="all" || FNR==line{
    print "DataFileName: " FILENAME
    print "Line "FNR
    id=getField(1,a[1])
    fn=getField(1+a[1],a[2])
    ln=getField(1+a[1]+a[2],a[3])
    print "ID:"id
    print "First Name: "fn
    print "Last Name: "ln
}

function getField(a,b,str) {
    str=substr($0,a,b)
    sub(/^[[:blank:]]+/,"",str)
    sub(/[[:blank:]]$/,"",str)
    return str
}

带输出:

DataFileName: customer.dat
Line 1
ID:1234567890
First Name: John                
Last Name: Armless
DataFileName: customer.dat
Line 2
ID:9         
First Name: Eric                
Last Name: Clapton             
DataFileName: customer.dat
Line 3
ID:10        
First Name: Roger               
Last Name: Waters

答案 1 :(得分:3)

这里有更通用的方法来处理它而无需对列名进行硬编码。这将允许在不同的文件上运行代码。

NF > 1 {
colwidth[FNR]=$2
colname[FNR]=$1
++colcount
}

NF < 2 {
        if(line=="all" || FNR==line) {
                printf("DataFileName: %s\n",FILENAME)
                printf("Line %d\n",FNR)
                nextcol=1
                for(eachcol=1; eachcol <= colcount; eachcol++ ) {
                        printf("%s : %s\n",colname[eachcol],substr($0,nextcol,colwidth[eachcol]))
                        nextcol+=colwidth[eachcol]
                }
        }
}

这是我运行上述代码时得到的结果。我将代码保存为/tmp/p.awk。

**awk -v line=2 -f /tmp/p.awk -F";" /tmp/customer.cfg /tmp/customer.dat**
DataFileName: /tmp/customer.dat
Line 2
ID  : 9
First Name  : Eric
Last Name  : Clapton

**awk -v line=all -f /tmp/p.awk -F";" /tmp/customer.cfg /tmp/customer.dat**
DataFileName: /tmp/customer.dat
Line 1
ID  : 1234567890
First Name  : John
Last Name  : Armless
DataFileName: /tmp/customer.dat
Line 2
ID  : 9
First Name  : Eric
Last Name  : Clapton
DataFileName: /tmp/customer.dat
Line 3
ID  : 10
First Name  : Roger
Last Name  : Waters

答案 2 :(得分:2)

@HåkonHægland 我改变了一些你的代码以使其足够通用,所以现在我可以将它用于我在这里的任何* .dat * .cfg文件。

NR==FNR {
    a[++i]=$2
    b[i]=$1
    next
}

line=="all" || FNR==line{
    print "DataFileName: " FILENAME
    print "Line: "FNR
    linePos=1
    for (j=1;j<=i;j++){
      print b[j]":" getField(linePos,a[j])
      linePos+=a[j]
    }
    print "\n"
}

function getField(a,b,str) {
    str=substr($0,a,b)
    sub(/^[[:blank:]]+/,"",str)
    sub(/[[:blank:]]$/,"",str)
    return str
}

再次感谢。