awk がこの行を複数回印刷するのはなぜですか?

awk がこの行を複数回印刷するのはなぜですか?

次の 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 回だけ印刷したいのですが。

答え1

この条件は/^mail:/後続のすべての命令には影響せず、最初の命令 ( mail = $2) にのみ影響します。

その結果、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入力行全体にわたって変数が設定されるため、次に入力行が条件文に一致するまで、古い値が何度も再利用されます。

関連情報