awk 模式匹配和处理缺失字段



我从ldapsearch的输出中得到了一些数据,如下所示:

> echo "$OUTPUT"
sn: name1
uid: uname1
mail: user1@mail.com
roomNumber: e2
sn: name2
uid: uname2
mail: user2@mail.com
roomNumber: e2
sn: name3
uid: uname3
roomNumber: e2
sn: name4
uid: uname4
mail: user4@mail.com
roomNumber: e2

我正在使用awk将每个用户处理成一行,以便它最终像这样结束:

name1|uname1|user1@mail.com|e2
name2|uname2|user2@mail.com|e2
name3|uname3||e2
name4|uname4|user4@mail.com|e2

问题是我下面的代码无法处理缺少的 mail 属性,因此它重用了上一个用户的变量,如下所示:

name1|uname1|user1@mail.com|e2
name2|uname2|user2@mail.com|e2
name3|uname3|user2@mail.com|e2
name4|uname4|user4@mail.com|e2

使用的 awk 命令是:

echo "$OUTPUT" | awk -v OFS='|' '{split($0,a,": ")} 
/^sn:/{sn=a[2]} 
/^uid:/{uid=a[2]} 
/^mail:/{mail=a[2]} 
/^roomNumber:/{room=a[2]; print sn, uid, mail, room}'

有没有办法处理上面示例中缺少的属性,例如邮件?

谢谢。

正如您所注意到的,您的输入在记录中的结构非常好。每条记录由一组空行分隔。你可以用awk来利用这一点。

下面的思想是读取每个多行记录,其键值对的形式为 (key: value(

sn: name2
uid: uname2
mail: user2@mail.com
roomNumber: e2

我们将告诉awk相应地提取该信息并将其存储在数组data中。然后,我们将使用此数组以您想要的方式重建数据。如果记录中不存在某个键,它将在请求时返回一个空值:

awk 'BEGIN{RS=""; FS="n"; OFS="|"}
{ delete data; }
{ for(i=1;i<=NF;++i) {
match($i,/: +/);
key=substr($i,1,RSTART-1); value=substr($i,RSTART+RLENGTH);
data[key]=value }
}
{ print data["sn"], data["uid"], data["mail"], data["roomNumber"] }' file

此方法非常通用且非常灵活,如果您以后想更改任何内容。

在给出的示例中,此输出:

name1|uname1|user1@mail.com|e2
name2|uname2|user2@mail.com|e2
name3|uname3||e2
name4|uname4|user4@mail.com|e2

假设每条记录的输入行始终按所示排序,并且可能缺少的只是电子邮件字段:

$ awk -v RS= -F': |n' -v OFS='|' '{print $2, $4, (NF>6 ? $6 : ""), $NF}' file
name1|uname1|user1@mail.com|e2
name2|uname2|user2@mail.com|e2
name3|uname3||e2
name4|uname4|user4@mail.com|e2

只需在打印后将变量设置为空字符串:

$ awk -v OFS='|' '{split($0,a,": ")} 
/^sn:/{sn=a[2]} 
/^uid:/{uid=a[2]} 
/^mail:/{mail=a[2]} 
/^roomNumber:/{room=a[2]; print sn, uid, mail, room; sn=uid=mail=room=""}' file
name1|uname1|user1@mail.com|e2
name2|uname2|user2@mail.com|e2
name3|uname3||e2
name4|uname4|user4@mail.com|e2

最新更新