使用awk将行转换为列

时间:2014-07-21 15:42:44

标签: awk sed

并非所有列(& data)都存在于所有记录中。因此,每当缺少字段缺失时,应将其替换为空值。

我的输入格式:

    .set 1000  
EMP_NAME="Rob"  
EMP_DES="Developer"  
EMP_DEP="Sales"  
EMP_DOJ="20-10-2010"  
EMR_MGR="Jack"      
     .set 1001  
EMP_NAME="Koster"  
EMP_DEP="Promotions"  
EMP_DOJ="20-10-2011"      
    .set 1002  
EMP_NAME="Boua"  
EMP_DES="TA"  
EMR_MGR="James"  

我想要的输出格式:

Rob~Developer~Sales~20-10-2010~Jack  
Koster~~Promotions~20-10-2011~  
Boua~TA~~~James

我尝试了以下内容:

awk 'NR>1{printf "%s"(/^\.set/?RS:"~"),a} {a=substr($0,index($0,"=")+1)} END {print a}' $line

这是打印:

Rob~Developer~Sales~20-10-2010~Jack  
Koster~Promotions~20-10-2011~  
Boua~TA~James~

3 个答案:

答案 0 :(得分:0)

这个awk脚本产生了所需的输出:

BEGIN { FS = "[=\"]+"; OFS = "~" }

/\.set/ { ++records; next }

NR > 1 { f[records,$1] = $2 }

END {    
    for (i = 1; i <= records; ++i) {
        print f[i,"EMP_NAME"], f[i,"EMP_DES"], f[i,"EMP_DEP"], f[i,"EMP_DOJ"], f[i,"EMR_MGR"]
    }
}

二维数组用于存储为每条记录定义的所有值。

在处理完所有文件后,循环遍历数组的每一行并打印所有值。未定义的元素将被计算为空字符串。

指定元素明确性允许您控制它们的打印顺序。使用print而不是printf可以正确使用已设置为OFS的{​​{1}}变量,以及~默认情况下换行符。

感谢his helpful comments的@Ed指出我原始剧本中的一些缺陷。

输出:

ORS

答案 1 :(得分:0)

$ cat tst.awk
BEGIN{ FS="[=\"]+"; OFS="~" }
/\.set/ { ++numRecs; next }
{ name2val[numRecs,$1] = $2 }
!seen[$1]++ { names[++numNames] = $1 }
END {
    for (recNr=1; recNr<=numRecs; recNr++)
        for (nameNr=1; nameNr<=numNames; nameNr++)
            printf "%s%s", name2val[recNr,names[nameNr]], (nameNr<numNames?OFS:ORS)
}

$ awk -f tst.awk file
Rob~Developer~Sales~20-10-2010~Jack
Koster~~Promotions~20-10-2011~
Boua~TA~~~James

如果您希望输出中有一些预定义的字段顺序,而不是在读取时从每个记录中的行动态创建它,只需在BEGIN中显式填充names[]数组部分,如果您有这种情况,并且不想将整个文件保存在内存中:

$ cat tst.awk
BEGIN{
    FS="[=\"]+"; OFS="~";
    numNames=split("EMP_NAME EMP_DES EMP_DEP EMP_DOJ EMR_MGR",names,/ /)
}
function prtName2val(   nameNr, i) {
    if ( length(name2val) ) {
        for (nameNr=1; nameNr<=numNames; nameNr++)
            printf "%s%s", name2val[names[nameNr]], (nameNr<numNames?OFS:ORS)
        delete name2val
    }
}
/\.set/ { prtName2val(); next }
{ name2val[$1] = $2 }
END { prtName2val() }

$ awk -f tst.awk file
Rob~Developer~Sales~20-10-2010~Jack
Koster~~Promotions~20-10-2011~
Boua~TA~~~James

以上使用length(name2val)delete name2val的GNU awk,如果你没有,那么请使用for (i in name2val) { do stuff; break }split("",name2val)代替..

答案 2 :(得分:-1)

这就是我所能建议的:

awk '{ t = $0; sub(/^[^"]*"/, "", t); gsub(/"[^"]*"/, "~", t); sub(/".*/, "", t); print t }' file

或sed:

sed -re 's|^[^"]*"||; s|"[^"]*"|~|g; s|".*||' file

输出:

Rob~Developer~Sales~20-10-2010~Jack~Koster~Promotions~20-10-2011~Boua~TA~James