Как работает `getline` в AWK?

Я собрал пример, используя функцию 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 

Я думаю, что понимание того, как изменение NR во время цикла awk является ключом к пониманию этого результата.

  • Можете ли вы объяснить, почему мой ожидаемый результат неправильный и почему фактический результат прав?

Я запускаю awk version 20070501 на macOS 10.12.1

  • Вывод процесса `find` обрабатывает определенные поля
  • суммы столбцов на основе совпадающих полей
  • Грепируйте линии между появлением одного и того же шаблона
  • добавление букв и символов в столбец с помощью awk или sed?
  • если условие в bash-скриптинге
  • Awk / bash Keep line containg только 3 поля
  • awk для сопоставления и вырезания полей с чередующимся разделителем
  • Как grep несколько файлов, используя часть имени файла как шаблон?
  • 2 Solutions collect form web for “Как работает `getline` в AWK?”

    Я думаю, что вам не хватает в том, что при настройке NR getline по сути потребляет линию. Таким образом, при втором вызове bar уже ушел, а $0baz ; getline пытается прочитать другую строку и не удается; и значение tmp остается неизменным (т.е. равным bar ).

    Это может быть проще понять, если вы проверите возвращаемое значение getline :

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

    Должно быть ясно, если вы посмотрите на более крупную картину, так сказать. Программа 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 неизменным, и вы снова печатаете следующую строку.

    Linux и Unix - лучшая ОС в мире.