Вернуть только часть строки после соответствующего шаблона


109

Таким образом, открывание файла с помощью catи последующее использование grepдля получения совпадающих строк только уводит меня, когда я работаю с определенным набором журналов, с которым я имею дело. Нужен способ сопоставления линий с шаблоном, но только для возврата части строки после соответствия. Доля до и после матча будет постоянно меняться. Я играл с использованием sedили awk, но не смог выяснить, как отфильтровать строку, чтобы либо удалить часть до матча, либо просто вернуть часть после матча, либо сработает. Это пример строки, которую мне нужно отфильтровать:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

Часть, в которой я нуждаюсь, - это все, что после "остановлено".

Подоплекой этого является то, что я могу узнать, как часто что-то глохнет:

cat messages | grep stalled | wc -l

Что мне нужно сделать, это выяснить, сколько раз определенный узел останавливался (на что указывает часть перед каждым двоеточием после «остановленного»). Если я просто grep для этого (то есть 20 :), он может вернуть строки, которые имеют мягкие сбои, но нет остановок, что не помогает мне. Мне нужно отфильтровать только остановленную часть, чтобы я мог найти конкретный узел из тех, которые остановились.

По сути, это система freebsd со стандартными утилитами ядра GNU, но я не могу установить ничего, чтобы помочь.


@ Жиль, странно, как это не всплывало, когда я искал, хотя я не использовал название, с которым я в конце концов пошел ... но оно не показывалось на экране под моим названием. В любом случае, если не считать этого, это может привести меня туда, куда я хочу, хотя мне нужна вся строка после матча, а не первое слово - но, возможно, не потребуется много изменений.
MaQleod

Его название высосано. Я украл твой, что очень мило. Примите sedрешение и не обрабатывайте пробелы специально.
Жиль

@ Жиль, я не совсем уверен, как это сделать. Я все еще учусь Сед.
MaQleod


1
@ shaa0601 Я не понимаю ваш вопрос, особенно трудно следовать в комментариях без форматирования. Задайте новый, самостоятельный вопрос.
Жиль

Ответы:


141

Каноническим инструментом для этого будет sed.

sed -n -e 's/^.*stalled: //p'

Детальное объяснение:

  • -n означает не печатать ничего по умолчанию.
  • -e сопровождается командой sed.
  • s команда замены шаблона
  • Регулярное выражение ^.*stalled:соответствует шаблону, который вы ищете, плюс любой предыдущий текст ( .*имеется в виду любой текст, с инициалом, ^указывающим, что совпадение начинается в начале строки). Обратите внимание, что если stalled:в строке происходит несколько раз, это будет соответствовать последнему вхождению.
  • Совпадение, т.е. все в строке до stalled:, заменяется пустой строкой (т.е. удаляется).
  • Последнее pозначает печатать преобразованную строку.

Если вы хотите сохранить соответствующую часть, используйте обратную ссылку: \1в заменяемой части обозначается то, что находится внутри группы \(…\)в шаблоне. Здесь вы можете написать stalled:снова в запасной части; эта функция полезна, когда шаблон, который вы ищете, является более общим, чем простая строка.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Иногда вы захотите удалить часть строки после матча. Вы можете включить его в совпадение, добавив .*$в конце шаблона (любой текст, .*за которым следует конец строки $). Если вы не поместите эту часть в группу, на которую вы ссылаетесь в тексте замены, конец строки не будет в выводе.

В качестве дополнительной иллюстрации групп и обратных ссылок эта команда меняет местами часть перед совпадением и деталь после совпадения.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

Я попробовал первые два примера, и это, кажется, зависает. Я не получаю сообщение об ошибке, и при этом я не получаю новое приглашение, просто ничего.
MaQleod

2
@MaQleod О, он ожидает ввода на стандартном вводе, который здесь является терминалом, потому что вы не перенаправили его. Здесь вы будете выполнять перенаправление ввода sed … <messages, поскольку хотите обрабатывать данные из файла. Для того, чтобы воздействовать на данные , полученные с помощью другой команды, вы бы использовать трубу: somecommand | sed ….
Жиль

1
верно, конец дня отключился. Команда работает отлично, спасибо.
MaQleod

1
Лучшее объяснение, которое я видел до сих пор - спасибо!
Джон Уодсворт

1
@ungalcrys более короткая версия чего? Это не эквивалентно ни одной из команд в моем ответе. Я бы порекомендовал написать его, sed 's/^.*stalled//'поскольку -rон специфичен для Linux и не работает на других системах, таких как macOS, и здесь вы не получаете никакой выгоды от него.
Жиль

72

Другой канонический инструмент, который вы уже используете grep:

Например:

grep -o 'stalled.*'

Имеет тот же результат, что и второй вариант Жиля:

sed -n -e 's/^.*\(stalled: \)/\1/p'

-oФлаг возвращает --only-matchingчасть выражения, поэтому не вся линия, - конечно - обычно делается Grep.

Чтобы убрать «stalled:» из вывода, мы можем использовать третий канонический инструмент, cut:

grep -o 'stalled.*' | cut -f2- -d:

Команда cutиспользует разделитель :и печатает поле 2 до конца. Конечно, это вопрос предпочтений, но cutсинтаксис, который я нахожу, очень легко запомнить.


1
Спасибо за упоминание -oопции! Я хотел указать, что grepне распознает символ \nновой строки, поэтому ваш первый пример соответствует только первому nсимволу. Например, echo "Hello Anne" | grep -o 'A[^\n]*'возвращает строку A. Однако echo "Hello Anne" | grep -o 'A.*'возвращает ожидаемое Anne, поскольку .соответствует любому символу, кроме новой строки.
Адамламар

1
Обратите внимание, что кавычки вокруг cutразделителя -d':'удаляются @poige. Мне легче запоминать с помощью кавычек, например, с помощью -d' 'или -d';'.
Анна Ван Россум

В соответствии с вашими выводами, вам также будет проще помнить использовать кавычки -f 2. Серьезно, почему бы и нет?
Пойдж

Поскольку разделитель, такой как точка с запятой, ;а не двоеточие, :будет интерпретирован по-разному, если не будет заключен в кавычки. Конечно, это логичное поведение, но все же мне нравится полагаться на мышечную память. Я не люблю цитировать разделитель один раз, но не в другой раз. Просто личные предпочтения, как я уже говорил: легче запомнить.
Энн ван Россум

период, который является частью .*необходим, хорошо работал для меня: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' возвращаетсяxyz text
Рон

4

Я имел обыкновение ifconfig | grep eth0 | cut -f3- -d:брать это

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

и сделать так, чтобы это выглядело так

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
Это отвечает на вопрос?
Стивен Раух

1
Вы можете использовать cat /sys/class/net/*/address, анализ не требуется.
Энн ван Россум

1

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

awk -F"stalled" '/stalled/{print $2}' messages

Детальное объяснение:

  • -Fопределяет разделитель для строки, т. е. «остановлен». Все до разделителя адресовано $1и все после с $2.
  • /reg-ex/ Ищет подходящее регулярное выражение, в этом случае "остановлено".
  • {print $<n>}- печатает столбец n. Поскольку ваш разделитель определен как остановленный, все после остановленного считается вторым столбцом.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.