AWK 中的「getline」如何運作?

AWK 中的「getline」如何運作?

我已經使用 AWK 函數編寫了一個範例getline,但它讓我感到困惑。

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

我正在將下一行讀入一個名為的變量,tmp該變量不會發生變化$0,正如前兩行輸出所確認的那樣:

bar
foo

下表證實了這一點AWK 程式語言第 62 頁:

在此輸入影像描述

我知道NRFNR內建函數代表到目前為止已讀取的行數。我認為這是理解正在發生的事情的關鍵,但我很困惑NR在一次傳球時的改變如何影響未來的傳球。

我預計接下來的兩行是:

baz
bar

因為在第二遍時$0 == bartmp == baz

然後我期望接下來的兩行其實只是一行:

baz

因為在第三遍時$0 == baztmp == null

所以我的預期輸出是:

bar
foo
baz
bar
baz

我認為理解 awk 循環中 while 的變化NR是理解這個輸出的關鍵。

  • 你能解釋為什麼我的預期輸出是錯的嗎為什麼實際輸出是正確的?

我正在awk version 20070501奔跑macOS 10.12.1

答案1

我認為你缺少的是,在設定中NRgetline實際上消耗線。所以在第二次呼叫時,baris 已經消失了,並且$0baz;getline嘗試讀取另一行但失敗;且 的值tmp保持不變(即等於bar)。

如果你檢查一下返回值可能會更容易理解getline

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

答案2

可以這麼說,如果你看一下更大的圖景,就會變得很清楚。 awk 程式是圍繞程式文字的循環,它會讀取一行,然後執行該行上的程式。如果您在程式內讀取一行,則周圍的迴圈不會看到該行:它已經被消耗了。

例如,你的程式

{ getline tmp; print tmp; print $0 }

可以寫成

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

BEGIN區塊在程式開始時執行一次,此時程式不執行任何其他操作 — 當然,這是一種非常不慣用的編寫 awk 程式碼的方式。

這裡應該清楚發生的事情是:

  • 將第 1 行讀取到$0第一行getline
  • 將第 2 行讀至tmp第二行getline
  • tmp然後列印$0,即列印第 2 行,然後列印第 1 行
  • 重複下一對行:列印第 4 行,然後列印第 3 行,依此類推。

對於奇數行,最後一行經過getline $0,然後getline tmp失敗,但您沒有檢查返回狀態,因此這只是保持tmp不變,最終再次列印倒數第二行。

相關內容