我有以下 ldif:
dn: cn=Robert Smith,ou=people,dc=example,dc=com
objectclass: inetOrgPerson
cn: Robert Smith
cn: Robert J Smith
cn: bob smith
sn: smith
uid: rjsmith
userpassword: rJsmitH
carlicense: HISCAR 123
homephone: 555-111-2222
mail: [email protected]
alias: [email protected]
alias: [email protected]
description: nice hair
ou: Human Resources
dn: cn=John Doe,ou=people,dc=example,dc=com
objectclass: inetOrgPerson
cn: John Doe
cn: John Walker Doe
cn: Johnny
sn: Doe
uid: jdoe
userpassword: topsecret
carlicense: AKAHH 123
homephone: 123-458-362
mail: [email protected]
alias: [email protected]
alias: [email protected]
description: cool guy
ou: Sales
现在我正在对其运行 awk 命令:
awk '/^mail:/ { mail = $2 }; {print mail };' ldif
预期结果是:
[email protected]
[email protected]
实际结果是:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
我不太明白为什么 awk 会多次给出这个输出。如果有人能给我解释一下,我将不胜感激,因为我刚接触 awk,之前很少使用它。我已经查阅了手册页和 Google,但我想我找错了地方...
编辑:我理解 awk 以行的形式处理文本流。我猜我的“print”只是按照 ldif 文件中的行数打印输出。但我如何才能阻止 awk 这样做呢?我只想打印每个结果一次。
答案1
该条件/^mail:/
不会影响后面的所有指令,只影响第一个指令(mail = $2
)。
因此,第二条指令(print mail
)被执行每一行。
这就是为什么输出开始处实际上有几行空白行(mail
尚未设置)。
以下任何一种方法都可以:
awk '/^mail:/ { { mail=$2 }; {print mail } };' ldif
awk '/^mail:/ { mail=$2; print mail };' ldif
就我个人而言,我更喜欢:
awk '/^mail:/ { print $2 }' ldif
答案2
@Dennis 提供了一个提供正确语法的解决方案,但并没有完全回答最初的问题“为什么 awk 多次打印这一行?”
Awk 以面向行的循环运行,除了少数例外(例如 BEGIN 和 END)外,它会在输入的每一行上运行整个脚本。在 OP 的示例中,针对输入文件的每一行运行以下伪代码:
if LINE starts with "mail:"
set MAIL to value of second field of the input record
endif
print MAIL
输出重复行的原因是 print 语句是外部条件语句,因此执行每一个输入行,而不仅仅是与正则表达式匹配的行。此外,由于变量mail
仅在条件语句内设置,因此旧值会反复使用,直到下一次输入行与条件语句匹配。