我已經使用 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 頁:
我知道NR
和FNR
內建函數代表到目前為止已讀取的行數。我認為這是理解正在發生的事情的關鍵,但我很困惑NR
在一次傳球時的改變如何影響未來的傳球。
我預計接下來的兩行是:
baz
bar
因為在第二遍時$0 == bar
和tmp == baz
。
然後我期望接下來的兩行其實只是一行:
baz
因為在第三遍時$0 == baz
和tmp == null
。
所以我的預期輸出是:
bar
foo
baz
bar
baz
我認為理解 awk 循環中 while 的變化NR
是理解這個輸出的關鍵。
- 你能解釋為什麼我的預期輸出是錯的嗎和為什麼實際輸出是正確的?
我正在awk version 20070501
奔跑macOS 10.12.1
答案1
我認為你缺少的是,在設定中NR
,getline
實際上消耗線。所以在第二次呼叫時,bar
is 已經消失了,並且$0
是baz
;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
不變,最終再次列印倒數第二行。