Я составил пример с использованием getline
функции AWK, и он меня сбивает с толку.
$ 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
Я думаю, что понимание того, как происходит изменение NR
в цикле awk, является ключом к пониманию этого вывода.
- Можете ли вы объяснить, почему мой ожидаемый результат неверен?ипочему фактический результат правильный?
Я бегу awk version 20070501
дальшеmacOS 10.12.1
решение1
Я думаю, что вы упускаете из виду то, что в установке NR
, getline
по сути ,потребляетстрока. Так что при втором вызове bar
уже нет и $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
неизменным, и в итоге вы снова печатаете предпоследнюю строку.