Grep регистрационен файл за последното срещане на низ между два низа

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

Допълнителен кредит: По някакъв начин мога да върна съдържанието, съдържащо се в двата низа, само ако съдържанието съдържа "testString"?

Благодаря, че потърси.

РЕДАКТИРАНЕ: Параметрите за търсене и се съдържат на различни редове с около 100 реда съдържание, които ги разделят. Съдържанието е това, което преследвам...


person rs79    schedule 30.10.2013    source източник
comment
Примери за въвеждане може да помогнат; не е ясно дали таговете са на един ред или на различни.   -  person devnull    schedule 30.10.2013
comment
етикетите са на различни редове ..и разглеждаме около 70-100 реда съдържание в етикетите.   -  person rs79    schedule 30.10.2013
comment
Вместо да поставяте тази информация в коментарите, актуализирайте въпроса си. Очевидно отговорите, които сте получили, предполагат, че етикетите са на един и същи ред.   -  person devnull    schedule 30.10.2013


Отговори (5)


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

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

Тест

Предвид този файл

$ 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

Актуализация

РЕДАКТИРАНЕ: Параметрите за търсене и се съдържат на различни редове с около 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>

Тест

Даден файл 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
person fedorqui 'SO stop harming'    schedule 30.10.2013

Ако като мен нямате достъп до tac, защото вашият системен администратор не иска да играе, можете да опитате:

grep pattern file | tail -1
person SlackGadget    schedule 12.11.2014
comment
Благодаря, това трябва да е правилният отговор. тъй като tac ще се забърква с номерата на редовете в изхода, tail -1 свърши работа - person Bruno Rocha - rochacbruno; 21.09.2016
comment
също- так- не е стандартен за всички системи - person koolunix; 07.10.2016
comment
Имайте предвид обаче, че това не взема предвид частта между два низа. - person fedorqui 'SO stop harming'; 29.11.2016

Друго решение от 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.

person pfnuesel    schedule 30.10.2013

Малко непроверено 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

Започваме просто да четем файла; когато ударим , започваме да поддържаме линии. Когато ударим , спираме. Ако ударим друг, изчистваме задържания низ и започваме отначало. Ако искате всички низове, отпечатайте на всеки

person mpez0    schedule 30.10.2013

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
person Vorsprung    schedule 30.10.2013