Безопасно ли использовать getline в команде awk?

Безопасно ли использовать getline в команде awk?

Я получил странные комментарии, разместив awkна SO ответ, в котором используется эта getlineфункция. Здесьэто ссылка на этот ответ.

После публикации моего ответа пользователь оставил следующий комментарий ( я его не критикую ) .

Не очень хорошее решение, оно будет объединять строки независимо от содержимого и не обрабатывать больше строк, если это необходимо. И вам следует избегать использования getline.

Там говорится, что нам следует избегать getlineфункции в awk. Поэтому мои вопросы таковы:

  • Безопасно ли использовать getlineфункцию в awk?
  • В каких случаях следует использовать, а getlineв каких — нет?
  • Если эта функция дает неожиданные результаты, почему бы нам не отправить отчет об ошибке?

решение1

Большинство людей спорят о getlineтом,стиль кодированияземля.

Это чуждо обычной awkобработке, когда код обрабатывает одну запись за раз.

getline(когда не используется как getline var < "file"или "cmd" | getline) вытягивает следующую запись (возможно, из следующего файла) в середине оператора кода. Легко потерять тот факт, что он увеличивает NR, FNR, может изменить FILENAME.

Еще одна вещь, о которой не следует забывать при его использовании, — это проверка возвращаемого значения, поскольку оно вернет 0 при EOF или <0 в случае ошибки.

Так что это не getlineили if/while (getline) ..., это:

if/while ((getline) > 0) { .... }

Или:

if/while ((getline < "file") > 0) {...}

Большинство случаев использования getlineможно изменить, используя подход, подобный конечному автомату.

Вместо:

/pattern/ {getline; print}

Что, вероятно, неверно и должно быть написано так:

/pattern/ && (getline) > 0 {print}

Вы бы сделали:

found_pattern {print; found_pattern=0}
/pattern/{found_pattern=1}

Также обратите внимание, как эти два варианта отличаются, еслишаблонсопоставляется в двух последовательных строках.

Теперь, пока вы это знаете, getlineвсе в порядке. Если вы хотите обрабатывать несколько файлов одновременно, то вам нужно getline, но не забудьте проверить возвращаемое значение:

while ((getline a < "a") > 0 && (getline b < "b") > 0) {
  ....

Связанный контент