Подтвердить что ты не робот

Grep a Файл журнала для последнего вхождения строки между двумя строками

У меня есть файл журнала trace.log. В нем мне нужно grep для содержимого, содержащегося в строках <tag> и </tag>. Существует несколько наборов этой пары строк, и мне просто нужно вернуть содержимое между последним набором (другими словами, из tail файла журнала).

Дополнительный кредит: каким-либо образом я могу вернуть содержимое, содержащееся в двух строках, только если содержимое содержит "testString"?

Спасибо, что посмотрели.

EDIT: параметры поиска и содержатся в разных строках, содержащих около 100 строк содержимого, разделяющих их. Содержание - это то, что мне нужно...

4b9b3361

Ответ 1

Используйте tac, чтобы распечатать файл в обратном порядке, а затем grep -m1, чтобы просто напечатать один результат. Посмотрите вперед и посмотрите вперед текст между <tag> и </tag>.

tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'

Test

Учитывая этот файл

$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and  last one</tag>

$ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
and  last one

Update

EDIT: параметры поиска и содержатся в разных строках с около 100 строк содержимого, разделяющих их. Содержание - это то, что я после того, как...

Тогда это немного сложнее:

tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
                /<tag>/   {p=0; split($0, a, "<tag>");  $0=a[2]; print; exit};
                p' | tac

Идея состоит в том, чтобы перевернуть файл и использовать флаг p, чтобы проверить, появился ли еще <tag> или нет. Он начнет печать, когда </tag> появится и закончится, когда появится <tag> (потому что мы читаем наоборот).

  • split($0, a, "</tag>"); $0=a[1]; получает данные до </tag>
  • split($0, a, "<tag>" ); $0=a[2]; получает данные после <tag>

Test

Для файла a выполните следующие действия:

<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>

some text<tag>tag is starting here
blabla
and ends here</tag>

Выход будет:

$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac
tag is starting here
blabla
and ends here

Ответ 2

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

grep pattern file | tail -1

Ответ 3

Другим решением, чем grep, будет sed:

tac file | sed -n '0,/<tag>\(.*\)<\/tag>/s//\1/p'

tac file печатает файл в обратном порядке (cat назад), затем sed переходит из строки ввода 0 в первое вхождение <tag>.*<\tag> и заменяет <tag>.*<\tag> только той частью, которая был внутри <tag>. Флаг p печатает вывод, который был подавлен -n.

Изменить: это не работает, если <tag> и </tag> находятся на разных строках. Мы можем использовать sed для этого:

tac file | sed -n '/<\/tag>/,$p; /<tag>/q' | sed 's/.*<tag>//; s/<\/tag>.*//' | tac

Снова мы используем tac для чтения файла назад, затем первая команда sed считывает с первого появления и завершает работу, когда находит. Распечатываются только строки между ними. Затем мы передаем его другому процессу sed, чтобы разбить и, наконец, снова изменить строки с помощью tac.

Ответ 4

perl -e '$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]' ex.txt

Дополнительный кредит: любым способом я могу вернуть содержимое, содержащееся в две строки, только если содержимое содержит "testString"?

perl -e '$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);' ex.txt

Ответ 5

Маленький непроверенный awk, который обрабатывает несколько строк:

awk '
    BEGIN    {retain="false"}
    /<\tag>/ {retain = retain + $0; keep="false"; next}
    /<tag>/  {keep = "true"; retain = $0; next}
    keep == "true" {retain = retain + $0}
    END {print retain}
' filename

Мы начинаем просто читать файл; Когда мы ударяем, мы начинаем держать линии. Когда мы ударим, остановимся. Если мы ударим другого, мы очистим сохраненную строку и начнем снова. Если вы хотите, чтобы все строки были напечатаны на каждом