sed или awk для удаления шаблона, включая новую строку

#bash #awk #sed #text-processing

#bash #awk #sed #обработка текста

Вопрос:

У меня есть файл журнала, который был объединен с stderr, который я пытаюсь очистить. Я могу изолировать и найти stderr «загрязнение», но я борюсь с одной незначительной деталью: удаление новой строки

Это отдельный стандартный вывод, который я пытаюсь восстановить:

 some message 1234556
more info foo bar
  

и это комбинированный файл stdout / stderr, от которого я пытаюсь избавиться от сообщений stderr:

 some message 1234/some/path ERROR
  more info only 1 line though
556
more info foo bar
  

итак, это текст, от которого я пытаюсь избавиться:

 /some/path ERROR
more info only 1 line though
  

включая новые строки, чтобы отдельный стандартный вывод был восстановлен.

Я вызываю:

 # get rid of the line AFTER the stderr start
sed -i".bak" -e '/ERROR/{n;d}' *.log

# get rid of the start of stderr
sed -i".bak" -r 's//some/path.*ERROR//' *.log
  

К сожалению, вывод теперь:

 some message 1234
556
more info foo bar
  

Обратите внимание, точка вставки сообщения stderr может быть произвольной (в середине строки или в начале, в любом месте). Единственное, что я могу предположить, это то, что stderr является двухстрочным и что он начинается с /some/path и содержит идентификатор ошибки ( ERROR или что-то еще). Кроме того, может быть несколько последующих сообщений stderr, таких как:

 some message 1234/some/path ERROR
  more info only 1 line though
/some/path ANOTHER_ERR
  more info only 1 line though
556
more info foo bar
  

что, я думаю, не представляет особой проблемы (существует только 2 вида, поэтому я могу запускать несколько разных совпадений ( ERROR и ANOTHER_ERR )). Мне также все равно, какой инструмент используется sed или awk

Комментарии:

1. Не могли бы вы прояснить пару вещей: (1) Почему у вас такой чересстрочный вывод? Вы отправляли выходные данные двух команд в один и тот же файл? (2) more info only всегда ли начинается с пробелов?

Ответ №1:

Вы можете использовать мощную опцию режима абзаца perl . Параметр -00 командной строки, который включает режим прерывания абзаца, то есть Perl считывает текст абзац за абзацем, а не строка за строкой (абзац — это текст между двумя или более символами новой строки).

 perl -00 -pe 's//.*(ERROR|ANOTHER_ERR)n.*n//g' file
  

Чтобы добавить модификацию на место, добавьте -i флаг, подобный sed

 perl -00 -pi -e 's//.*(ERROR|ANOTHER_ERR)n.*n//g' file
  

Ответ №2:

С GNU sed для -E и -z:

 $ sed -Ez 's:/some/path ERRORn[^n] n::g' file
some message 1234556
more info foo bar
  

и если у вас есть несколько ошибок для обработки, просто перечислите их или разделите в регулярном выражении:

 $ cat file
some message 1234/some/path ERROR
  more info only 1 line though
/some/path ANOTHER_ERR
  more info only 1 line though
556
more info foo bar

$ sed -Ez 's:/some/path (ERROR|ANOTHER_ERR)n[^n] n::g' file
some message 1234556
more info foo bar
  

В качестве альтернативы, с помощью GNU awk для RS с несколькими символами:

 $ awk -v RS='/some/path ERRORn[^n] n' -v ORS= '1' file
some message 1234556
more info foo bar
  

или, если вы предпочитаете:

 $ awk -v RS='^$' -v ORS= '{gsub("/some/path ERRORn[^n] n","")}1' file
some message 1234556
more info foo bar
  

Ответ №3:

Кажется идеальным для некоторых базовых sed. Просто используйте, чтобы вставить следующую строку в пространство шаблона. N

sed '/ERROR/{N;s//.*//;N;s/n//g}' input.log

  • N Добавьте следующую строку в пространство шаблона
  • Удалите все после косой черты (включая следующую строку)
  • N Добавьте следующую строку в пространство шаблона
  • Удалить все разрывы строк

Это недалеко от попыток операционной n системы.

Чтобы распространить это на более поздний образец, у вас есть переход к началу, чтобы посмотреть N , не привели ли команды к большему количеству строк ошибок в пространство шаблонов:

sed -E ':a /(ERROR|ANOTHER_ERR)/{N;s//.*//;N;s/n//g;b a}'

  • Используется -E для разрешения двух шаблонов в скобках
  • Добавьте метку :a
  • b a переходите обратно :a всякий раз, когда строка ошибки в пространстве шаблонов найдена и обработана.

Я предпочитаю избегать sed -z . Он будет считывать весь файл в пространство шаблонов, поэтому это может быть не лучшим выбором, если этот файл журнала длинный или если вы передаете активный поток в sed.

Ответ №4:

Другое решение sed без -z опции:

 $ sed -E -n '/ERROR/{s@/.*@@;h;n;n;H;n;H;x;s/n//;p}' input.log
some message 1234556
more info foo bar