如果我把一个字段清零,为什么awk会进行不同的OFS解析



通过增加可靠分隔符上的计数器来分析多行"记录"(将使用带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解析的其他字段,而不是在gsubs中混合。

我正在用分析它

$ 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将第一个输出为一个块(字符串?(,而将第二个解析并输出为一系列记录?

指定给任何字段(例如,第二个脚本中的$1=""(具体地"告诉"awk重新编译当前记录($0(,用OFS替换每个FS

以下是如何真正做到你想做的事情:

$ 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,不需要将整个文件存储在内存中,不需要在多个位置提供显式标记名,只需在split("uid cn",tags)中列出想要输出的标记即可。事实上,如果您只是想将所有字段打印为CSV,而不想为输出重新排序,并且它们都存在于每个记录中,就像您的示例输入中一样,那么您根本不需要提及它们。以下是如何从这样一个由空行分隔的记录和冒号分隔的标签组成的文件中生成有效的CSV(例如,可以读取到Excel中(:如您在问题中所示的值:

$ cat tst.awk
NF {
tag = val = $0
sub(/:.*/,"",tag)
sub(/[^:]*:[[:space:]]*/,"",val)
tag2val[tag] = val
tags[++numTags] = tag
next
}
{ prt() }
END { prt() }
function prt(   tagNr,tag,val) {
OFS=","
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]
gsub(/"/,"""",val)
printf ""%s"%s", val, (tagNr<numTags ? OFS : ORS)
}
delete tag2val
numTags = 0
}
$ awk -f tst.awk file
"dn","objectClass","cn","uid","creationTime","uidNumber"
"uid=asd,ou=People,dc=MY,dc=ORG","...","Adam Saddler","asd","20110409131545-0700","1234"
"uid=mfwth,ou=People,dc=MY,dc=ORG","...","Mike Foksworth","mfwth","20160704144535-0800","12345"

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

这个GNU awk脚本可能会帮助你:

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

记录分离器CCD_ 14被设置为捕获由CCD_ 15或CCD_ 16或换行符分隔的记录。

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

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

最新更新