web-dev-qa-db-fra.com

Grep un fichier journal pour la dernière occurrence d'une chaîne entre deux chaînes

J'ai un fichier journal trace.log. J'y ai besoin de grep pour le contenu contenu dans les chaînes <tag> et </tag>. Il existe plusieurs ensembles de cette paire de chaînes et il me suffit de renvoyer le contenu entre le dernier ensemble (en d'autres termes, à partir de la variable tail du fichier journal).

Crédit supplémentaire: Est-ce que je peux retourner le contenu contenu dans les deux chaînes uniquement si le contenu contient "testString"? 

Merci d'avoir regardé.

EDIT: Les paramètres de recherche et sont contenus sur différentes lignes avec environ 100 lignes de contenu les séparant. Le contenu est ce que je suis après ...

24
rs79

Utilisez tac pour imprimer le fichier en sens inverse, puis grep -m1 pour n’imprimer qu’un seul résultat. Le regard en arrière et en avant vérifie le texte entre <tag> et </tag>.

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

Tester

Compte tenu de ce fichier

$ 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

Mettre à jour

EDIT: Les paramètres de recherche et sont contenus sur différentes lignes avec environ 100 lignes de contenu les séparant. Le contenu est ce que je suis après...

Alors c'est un peu plus compliqué:

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

L'idée est d'inverser le fichier et d'utiliser un indicateur p pour vérifier si le <tag> est déjà apparu ou non. L'impression commencera lorsque </tag> apparaîtra et se terminera lorsque <tag> arrivera (parce que nous lisons dans l'autre sens).

  • split($0, a, "</tag>"); $0=a[1]; récupère les données avant </tag>
  • split($0, a, "<tag>" ); $0=a[2]; récupère les données après <tag>

Tester

Étant donné un fichier a comme ceci:

<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>

La sortie sera:

$ 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
33
fedorqui

Si comme moi, vous n'avez pas accès à tac car votre administrateur système ne jouera pas au ballon, vous pouvez essayer:

grep pattern file | tail -1
22
SlackGadget

Une autre solution que grep serait séduite:

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

tac file imprime le fichier dans l'ordre inverse (cat en arrière), puis sed passe de la ligne de saisie 0 à la première occurrence de <tag>.*<\tag> et substitue <tag>.*<\tag> par la seule partie se trouvant dans <tag>. L'indicateur p imprime la sortie, qui a été supprimée par -n.

Edit: Cela ne fonctionne pas si <tag> et </tag> sont sur des lignes différentes. Nous pouvons toujours utiliser sed pour cela:

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

De nouveau, nous utilisons tac pour lire le fichier à l'envers, puis la première commande sed lit à partir de la première occurrence de et se ferme quand elle le trouve. Seules les lignes entre les deux sont imprimées. Ensuite, nous passons le processus à un autre processus sed pour le dépouiller et finalement inverser les lignes avec tac.

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

Crédit supplémentaire: De toute façon, je peux retourner le contenu contenu dans le deux chaînes uniquement si le contenu contient "testString"?

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

Un peu non testé awk qui gère plusieurs lignes:

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

Nous commençons juste à lire le fichier; lorsque nous atteignons la, nous commençons à garder des lignes. Quand on frappe le, on s'arrête. Si nous en touchons un autre, nous effaçons la chaîne conservée et recommençons. Si vous voulez toutes les chaînes, imprimez à chaque 

0
mpez0