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