如果我将字段清零,awk为什么要进行不同的OFS解析?

时间:2018-07-10 09:29:55

标签: awk

通过在可靠的分隔符上增加计数器来解析多行“记录”(将/^$/与sed一起使用。

解析如下所示的ldif(但我希望它能与其他记录类型(例如creationTime)快速通用化

dn: uid=asd,ou=People,dc=MY,dc=ORG
objectClass: ...
cn: Adam Saddler
uid: asd 
creationTime: 20110409131545-0700
uidNumber: 1234

dn: uid=mfwth,ou=People,dc=MY,dc=ORG
objectClass: ...
cn: Mike Foksworth
uid: mfwth
creationTime: 20160704144535-0800
uidNumber: 12345

并希望能够生成

uid, cn, ...
asd, Adam Saddler, ...
mfwth, Mike Foksworth, ...

我想让...解析awk的其他字段,而不是混入gsub s。

我正在用

进行解析
$ awk
 -vOFS=';'
 /dn/{ i++ }
 /cn/{ users[i]["cn"]=$0 }
 /uid/{ users[i]["uid"]=$0 }
 END{ for (j in users) print users[j]["uid"] "_" users[j]["cn"] }'

并获取(_是'_',制表符或空格)

uid: asd_cn: Adam Saddler
uid: mfwth_cn: Mike Foksworth

相反,在存储/xx/ { $1="" ; ... }之前修改匹配项

$ awk
 -vOFS=';'
 /dn/{ i++ }
 /cn/{ $1="" ; users[i]["cn"]=$0 }
 /uid/{ $1="" ; users[i]["uid"]=$0 }
 END{ for (j in users) print users[j]["uid"] " " users[j]["cn"] }'

似乎使输出字段分隔符(OFS)再次相关?

;asd; Adam;Saddler
;mfwth; Mike;Foksworth

为什么awk将第一个作为一个块(字符串?)输出,而将第二个作为一组记录进行解析并输出?

2 个答案:

答案 0 :(得分:1)

分配给任何字段(例如,第二个脚本中的$1="")明确要求awk重新编译当前记录($0),并用FS替换每个OFS。 / p>

这是如何真正做您想做的事情:

$ cat tst.awk
NF {
    tag = val = $0
    sub(/:.*/,"",tag)
    sub(/[^:]*:[[:space:]]*/,"",val)
    tag2val[tag] = val
    next
}
{ prt() }
END { prt() }
function prt(   tagNr,tags,numTags,tag,val) {
    OFS=", "
    numTags = split("uid cn",tags)
    if ( ++numRecs == 1 ) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            tag = tags[tagNr]
            printf "%s%s", tag, (tagNr<numTags ? OFS : ORS)
        }
    }
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        val = tag2val[tag]
        printf "%s%s", val, (tagNr<numTags ? OFS : ORS)
    }
    delete tag2val
}

$ awk -f tst.awk file
uid, cn
asd, Adam Saddler
mfwth, Mike Foksworth

请注意,以上代码不需要GNU awk,不需要将整个文件存储在内存中,不需要您在多个位置提供明确的标签名称,只需在{{ 1}}。实际上,如果您只是想将所有字段都以CSV格式打印,并且不想为输出重新排序,并且它们都出现在每条记录中,例如您的示例输入中,那么您就无需提及它们完全没有这是从带有冒号分隔标记的空白行分隔记录文件中生成有效CSV(例如可以读入Excel)的方法:值类似于问题中显示的值:

split("uid cn",tags)

答案 1 :(得分:0)

如果我的理解正确,您想提取=:字符之后的字段。

此GNU awk脚本可能会帮助您:

awk 'BEGIN{
      RS="\n\ndn: |,|\n"
      FS="[=:] *"
    }
    NF{a=a (a?",":"")$2}
    RT~/dn:/{print a;a=""}
    END{print a}' file

设置记录分隔符RS使其捕获由dn:,或换行符分隔的记录。

字段分隔符设置为使用:=拆分关键字和值。

main语句用所有值填充变量a。找到dn:关键字时或在文件末尾时,将打印变量a