#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