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不变,最终再次打印倒数第二行。

相关内容