AWK — код не выполняется последовательно в рамках правила END

Я обрабатываю один файл, создавая два разных ассоциативных массива для подсчета частоты двух разных шаблонов (т.е. полей 3 и 6, если они найдены).

Образец файла:

2019-06-20 : INFO : XYZ_6789 : [Command [cmd_zip_files]:] Standard output and error
2019-06-20 : INFO : ABC_1234 : License issue
Line with no timestamp
2019-06-20 : INFO : XYZ_6789 : [Command [cmd_zip_files]:] Standard output and error
2019-06-20 : INFO : ABC_1234 : License issue

Я хочу напечатать оба массива в конце, но их выходы перекрываются.

Я использую GNU Awk 4.1.3.

Я пытался использовать операторы «далее/продолжить», но они не кажутся ответом.

Возможно, я неправильно использую правило END.

#!/usr/bin/env awk

BEGIN {
  FS = "\\)? : \\(?| \\| |[][]"
  MSG_COL=3
  CMD_COL=6
  SEP = "================= = "
}

{
  if (match ($MSG_COL, /^[A-Z]{3}_[0-9]+/))
      msg_count[$MSG_COL]++

  if ($MSG_COL == "XYZ_6789")
    cmd_count[$CMD_COL]++
}

END {

  print ">> Count of msg <<"

  for (msg in msg_count)
    if (msg_count[msg] > 0)
      print msg_count[msg], msg | "sort -n"

  print ">> Count of cmd <<"

  for (cmd in cmd_count)
    print cmd_count[cmd], cmd | "sort -n"

}

Я ожидаю, что мой код выдаст следующий результат:

>> Count of msg <<
2 ABC_1234
2 XYZ_6789
>> Count of cmd <<
2 cmd_zip_files

Хотя, я получаю это:

>> Count of msg <<
>> Count of cmd <<
2 ABC_1234
2 cmd_zip_files
2 XYZ_6789

Вы хотите явно close() каждую трубу.

tripleee 24.06.2019 11:28

@tripleee — Руководство пользователя GAWK указывает, что когда файл или канал открывается для вывода, awk запоминает имя файла или связанную с ним команду, и последующие записи в тот же файл или команду добавляются к предыдущим записям. Файл или канал остаются открытыми до выхода из awk. Если я либо удалю команду | sort -n, либо воспользуюсь вашим советом (т. е. использую close("sort -n")), вывод не будет перекрываться. Спасибо!

muxevola 25.06.2019 10:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
48
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы уже используете GNU Awk, вы сможете избежать подоболочек и внешних утилит, установив PROCINFO["sorted_in"]. Ниже я использовал @val_num_desc, который сортирует по убыванию числового значения (не по индексу):

awk -F ' : ' '
  /^2019/ {Msg[$3]++; if (split($4, A, "[][]") > 1) Cmd[A[3]]++}
  END {
    PROCINFO["sorted_in"] = "@val_num_desc"
    print ">> Count of msg <<"
    for(m in Msg) print Msg[m], m
    print ">> Count of cmd <<"
    for(c in Cmd) print Cmd[c], c
  }
' file
>> Count of msg <<
2 XYZ_6789
2 ABC_1234
>> Count of cmd <<
2 cmd_zip_files

Я не знал об этой расширенной функции GAWK. Спасибо, что нашли время, чтобы протестировать его и внести некоторые изменения в исходную реализацию. Хотя я не собираюсь использовать его, чтобы сделать код более переносимым, а также потому, что его значение является «глобальным» (т. е. оно влияет на весь обход массива для циклов). Я также хочу иметь возможность сортировать, используя разные поля (например, флаг сортировки -k).

muxevola 25.06.2019 18:28
Ответ принят как подходящий

Это происходит потому, что вы сами не закрываете открытые дескрипторы файлов. Awk закроет их для вас в конце концов, когда сценарий завершится, и в этот момент любой ожидающий буферизованный вывод будет сброшен, но порядок, в котором они закрываются, непредсказуем и ненадежен.

Измените блок END на явно close их в нужном вам порядке:

END {
  print ">> Count of msg <<"
  c = "sort -n"
  for (msg in msg_count)
    if (msg_count[msg] > 0)
      print msg_count[msg], msg | c
  close(c)

  print ">> Count of cmd <<"
  c = "sort -n"
  for (cmd in cmd_count)
    print cmd_count[cmd], cmd | c
  close(c)
}

Другие вопросы по теме