AWK で `getline` はどのように機能しますか?

AWK で `getline` はどのように機能しますか?

AWK 関数を使用して例を作成したのですgetlineが、混乱しています。

$ cat in
foo
bar
baz
$ awk '{ getline tmp; print tmp; print $0 }' in
bar
foo
bar
baz

次の行を という名前の変数に読み込んでいますが、出力の最初の 2 行で確認されるように、tmpこの変数は変更されません。$0

bar
foo

これは以下の表から確認できる。AWK プログラミング言語62ページ:

ここに画像の説明を入力してください

NR組み込みのおよび は、これまでに読み取られた行数を表すことはわかっています。これが何が起こっているかを理解するための鍵だと思いますが、パス中に変更すると将来のパスにどのような影響が及ぶのFNRかわかりません。NR

次の 2 行は次のようになると予想していました。

baz
bar

なぜなら、2 回目のパスで$0 == bartmp == baz.

そして、次の 2 行は実際には 1 行だけになると思っていました。

baz

なぜなら、3 回目のパスで$0 == baztmp == null.

したがって、期待される出力は次のようになります。

bar
foo
baz
bar
baz

NRawk ループ内でどのように変化するかを理解することが、この出力を理解する鍵になると思います。

  • 予想した出力が間違っている理由を説明していただけますかそして実際の出力が正しいのはなぜですか?

私は走っていawk version 20070501ますmacOS 10.12.1

答え1

あなたが見逃しているのは、設定においてNRgetline事実上消費する行。したがって、2 回目の呼び出しでは、はbarすでになくなっており になって$0いますbazgetline別の行を読み取ろうとしますが失敗します。また、 の値はtmp変更されません (つまり、 と等しくなりますbar)。

の戻り値を確認すると理解しやすくなるかもしれませんgetline:

awk '{ if ((getline tmp) > 0) print tmp; print $0 }' in
bar
foo
baz

答え2

いわば、全体像を見れば明らかになるはずです。awk プログラムは、プログラム テキストのループであり、1 行を読み取り、その行のプログラムを実行します。プログラム内の行を読み取る場合、周囲のループはこの行を参照できません。すでに消費されているためです。

たとえば、あなたのプログラム

{ getline tmp; print tmp; print $0 }

次のように書くことができる。

BEGIN {
    while (getline $0) {
        getline tmp; print tmp; print $0
    }
}

ブロックBEGINはプログラムの先頭で 1 回実行され、ここではプログラムは他に何も行いません。もちろん、これは awk コードの記述方法としては非常に非慣用的です。

ここで何が起こるかは明らかです:

  • 1行目から$0最初のgetline
  • tmp2行目を2番目に読んでくださいgetline
  • 印刷しtmpてから$0、つまり 2 行目を印刷してから 1 行目を印刷します。
  • 次の行のペアでも繰り返します。4 行目を印刷してから 3 行目を印刷します。

行数が奇数の場合、最後の行は を通過して失敗しますがgetline $0getline tmp戻りステータスをチェックしていないため、変更tmpされずにそのまま残り、最後から 2 番目の行が再度印刷されることになります。

関連情報